Merge changes I88f7f7e5,If6c1153d

* changes:
  Expand docs for animation listener
  A brave new world for window insets (11/n)
diff --git a/Android.bp b/Android.bp
index 15befae..7e97e66 100644
--- a/Android.bp
+++ b/Android.bp
@@ -104,6 +104,11 @@
         "core/java/android/app/backup/IRestoreObserver.aidl",
         "core/java/android/app/backup/IRestoreSession.aidl",
         "core/java/android/app/backup/ISelectBackupTransportCallback.aidl",
+        "core/java/android/app/contentsuggestions/IClassificationsCallback.aidl",
+        "core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl",
+        "core/java/android/app/contentsuggestions/ISelectionsCallback.aidl",
+        "core/java/android/app/prediction/IPredictionCallback.aidl",
+        "core/java/android/app/prediction/IPredictionManager.aidl",
         "core/java/android/app/role/IOnRoleHoldersChangedListener.aidl",
         "core/java/android/app/role/IRoleManager.aidl",
         "core/java/android/app/role/IRoleManagerCallback.aidl",
@@ -273,6 +278,7 @@
         "core/java/android/rolecontrollerservice/IRoleControllerService.aidl",
         ":keystore_aidl",
         "core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
+        "core/java/android/service/appprediction/IPredictionService.aidl",
         "core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl",
         "core/java/android/service/autofill/augmented/IFillCallback.aidl",
         "core/java/android/service/autofill/IAutoFillService.aidl",
@@ -282,6 +288,7 @@
         "core/java/android/service/carrier/ICarrierService.aidl",
         "core/java/android/service/carrier/ICarrierMessagingCallback.aidl",
         "core/java/android/service/carrier/ICarrierMessagingService.aidl",
+        "core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl",
         "core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl",
@@ -495,6 +502,7 @@
         "media/java/android/media/session/IOnMediaKeyListener.aidl",
         "media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl",
         "media/java/android/media/session/ISession.aidl",
+        "media/java/android/media/session/ISession2TokensListener.aidl",
         "media/java/android/media/session/ISessionCallback.aidl",
         "media/java/android/media/session/ISessionController.aidl",
         "media/java/android/media/session/ISessionControllerCallback.aidl",
@@ -593,7 +601,7 @@
         "telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
         "telephony/java/com/android/internal/telephony/ISms.aidl",
         "telephony/java/com/android/internal/telephony/ISub.aidl",
-        "telephony/java/com/android/internal/telephony/IAns.aidl",
+        "telephony/java/com/android/internal/telephony/IOns.aidl",
         "telephony/java/com/android/internal/telephony/ITelephony.aidl",
         "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl",
         "telephony/java/com/android/internal/telephony/IWapPushManager.aidl",
@@ -731,6 +739,7 @@
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.health-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java-constants",
+        "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
         "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
@@ -745,6 +754,7 @@
         "android.hardware.radio-V1.3-java",
         "android.hardware.radio-V1.4-java",
         "android.hardware.usb.gadget-V1.0-java",
+        "networkstack-aidl-interfaces-java",
         "netd_aidl_interface-java",
         "devicepolicyprotosnano",
     ],
@@ -872,11 +882,16 @@
     name: "networkstack-aidl-interfaces",
     local_include_dir: "core/java",
     srcs: [
+        "core/java/android/net/INetworkMonitor.aidl",
+        "core/java/android/net/INetworkMonitorCallbacks.aidl",
+        "core/java/android/net/IIpMemoryStore.aidl",
         "core/java/android/net/INetworkStackConnector.aidl",
         "core/java/android/net/INetworkStackStatusCallback.aidl",
+        "core/java/android/net/PrivateDnsConfigParcel.aidl",
         "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
         "core/java/android/net/dhcp/IDhcpServer.aidl",
         "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
+        "core/java/android/net/ipmemorystore/**/*.aidl",
     ],
     api_dir: "aidl/networkstack",
 }
diff --git a/api/current.txt b/api/current.txt
index 7e0c33c..584aedf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7379,7 +7379,9 @@
     method public boolean isRoleHeld(java.lang.String);
     field public static final java.lang.String ROLE_BROWSER = "android.app.role.BROWSER";
     field public static final java.lang.String ROLE_DIALER = "android.app.role.DIALER";
+    field public static final java.lang.String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
     field public static final java.lang.String ROLE_GALLERY = "android.app.role.GALLERY";
+    field public static final java.lang.String ROLE_HOME = "android.app.role.HOME";
     field public static final java.lang.String ROLE_MUSIC = "android.app.role.MUSIC";
     field public static final java.lang.String ROLE_SMS = "android.app.role.SMS";
   }
@@ -26076,6 +26078,46 @@
     field public static final int URI_COLUMN_INDEX = 2; // 0x2
   }
 
+  public final class Session2Command implements android.os.Parcelable {
+    ctor public Session2Command(int);
+    ctor public Session2Command(java.lang.String, android.os.Bundle);
+    method public int describeContents();
+    method public int getCommandCode();
+    method public java.lang.String getCustomCommand();
+    method public android.os.Bundle getExtras();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
+    field public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR;
+    field public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; // 0xffffffff
+    field public static final int RESULT_INFO_SKIPPED = 1; // 0x1
+    field public static final int RESULT_SUCCESS = 0; // 0x0
+  }
+
+  public static final class Session2Command.Result {
+    ctor public Session2Command.Result(int, android.os.Bundle);
+    method public int getResultCode();
+    method public android.os.Bundle getResultData();
+  }
+
+  public final class Session2CommandGroup implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.util.Set<android.media.Session2Command> getCommands();
+    method public boolean hasCommand(android.media.Session2Command);
+    method public boolean hasCommand(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.Session2CommandGroup> CREATOR;
+  }
+
+  public static final class Session2CommandGroup.Builder {
+    ctor public Session2CommandGroup.Builder();
+    ctor public Session2CommandGroup.Builder(android.media.Session2CommandGroup);
+    method public android.media.Session2CommandGroup.Builder addCommand(android.media.Session2Command);
+    method public android.media.Session2CommandGroup.Builder addCommand(int);
+    method public android.media.Session2CommandGroup build();
+    method public android.media.Session2CommandGroup.Builder removeCommand(android.media.Session2Command);
+    method public android.media.Session2CommandGroup.Builder removeCommand(int);
+  }
+
   public class SoundPool {
     ctor public deprecated SoundPool(int, int, int);
     method public final void autoPause();
@@ -27121,6 +27163,21 @@
 
 package android.media.session {
 
+  public final class ControllerCallbackLink implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.IBinder getBinder();
+    method public void notifyEvent(java.lang.String, android.os.Bundle);
+    method public void notifyExtrasChanged(android.os.Bundle);
+    method public void notifyMetadataChanged(android.media.MediaMetadata);
+    method public void notifyPlaybackStateChanged(android.media.session.PlaybackState);
+    method public void notifyQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
+    method public void notifyQueueTitleChanged(java.lang.CharSequence);
+    method public void notifySessionDestroyed();
+    method public void notifyVolumeInfoChanged(android.media.session.MediaController.PlaybackInfo);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.session.ControllerCallbackLink> CREATOR;
+  }
+
   public final class MediaController {
     ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
     method public void adjustVolume(int, int);
@@ -27355,6 +27412,36 @@
     method public android.media.session.PlaybackState.CustomAction.Builder setExtras(android.os.Bundle);
   }
 
+  public final class SessionCallbackLink implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.IBinder getBinder();
+    method public void notifyAdjustVolume(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
+    method public void notifyCommand(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void notifyCustomAction(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+    method public void notifyFastForward(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void notifyMediaButton(java.lang.String, int, int, android.content.Intent, int, android.os.ResultReceiver);
+    method public void notifyMediaButtonFromController(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.content.Intent);
+    method public void notifyNext(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void notifyPause(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void notifyPlay(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void notifyPlayFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+    method public void notifyPlayFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+    method public void notifyPlayFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
+    method public void notifyPrepare(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void notifyPrepareFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+    method public void notifyPrepareFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
+    method public void notifyPrepareFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
+    method public void notifyPrevious(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void notifyRate(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.media.Rating);
+    method public void notifyRewind(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void notifySeekTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
+    method public void notifySetVolumeTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
+    method public void notifySkipToTrack(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
+    method public void notifyStop(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.session.SessionCallbackLink> CREATOR;
+  }
+
 }
 
 package android.media.tv {
@@ -29415,7 +29502,7 @@
     field public java.lang.String SSID;
     field public java.util.BitSet allowedAuthAlgorithms;
     field public java.util.BitSet allowedGroupCiphers;
-    field public java.util.BitSet allowedGroupMgmtCiphers;
+    field public java.util.BitSet allowedGroupManagementCiphers;
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
@@ -29682,9 +29769,6 @@
     method public void setReferenceCounted(boolean);
   }
 
-  public static abstract class WifiManager.NetworkSuggestionsStatusCode implements java.lang.annotation.Annotation {
-  }
-
   public class WifiManager.WifiLock {
     method public void acquire();
     method public boolean isHeld();
@@ -30006,7 +30090,8 @@
     method public android.net.wifi.p2p.WifiP2pConfig build();
     method public android.net.wifi.p2p.WifiP2pConfig.Builder enablePersistentMode(boolean);
     method public android.net.wifi.p2p.WifiP2pConfig.Builder setDeviceAddress(android.net.MacAddress);
-    method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOwnerBand(int);
+    method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingBand(int);
+    method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingFrequency(int);
     method public android.net.wifi.p2p.WifiP2pConfig.Builder setNetworkName(java.lang.String);
     method public android.net.wifi.p2p.WifiP2pConfig.Builder setPassphrase(java.lang.String);
   }
@@ -34374,6 +34459,8 @@
     method public java.util.ArrayList<java.lang.String> createStringArrayList();
     method public <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
     method public <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
+    method public <T extends android.os.Parcelable> android.util.ArrayMap<java.lang.String, T> createTypedArrayMap(android.os.Parcelable.Creator<T>);
+    method public <T extends android.os.Parcelable> android.util.SparseArray<T> createTypedSparseArray(android.os.Parcelable.Creator<T>);
     method public int dataAvail();
     method public int dataCapacity();
     method public int dataPosition();
@@ -34415,7 +34502,7 @@
     method public java.io.Serializable readSerializable();
     method public android.util.Size readSize();
     method public android.util.SizeF readSizeF();
-    method public android.util.SparseArray readSparseArray(java.lang.ClassLoader);
+    method public <T> android.util.SparseArray<T> readSparseArray(java.lang.ClassLoader);
     method public android.util.SparseBooleanArray readSparseBooleanArray();
     method public java.lang.String readString();
     method public void readStringArray(java.lang.String[]);
@@ -34461,7 +34548,7 @@
     method public void writeSerializable(java.io.Serializable);
     method public void writeSize(android.util.Size);
     method public void writeSizeF(android.util.SizeF);
-    method public void writeSparseArray(android.util.SparseArray<java.lang.Object>);
+    method public <T> void writeSparseArray(android.util.SparseArray<T>);
     method public void writeSparseBooleanArray(android.util.SparseBooleanArray);
     method public void writeString(java.lang.String);
     method public void writeStringArray(java.lang.String[]);
@@ -34469,8 +34556,10 @@
     method public void writeStrongBinder(android.os.IBinder);
     method public void writeStrongInterface(android.os.IInterface);
     method public <T extends android.os.Parcelable> void writeTypedArray(T[], int);
+    method public <T extends android.os.Parcelable> void writeTypedArrayMap(android.util.ArrayMap<java.lang.String, T>, int);
     method public <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
     method public <T extends android.os.Parcelable> void writeTypedObject(T, int);
+    method public <T extends android.os.Parcelable> void writeTypedSparseArray(android.util.SparseArray<T>, int);
     method public void writeValue(java.lang.Object);
     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
   }
@@ -42662,6 +42751,7 @@
     method public static java.lang.String capabilitiesToString(int);
     method public android.telecom.PhoneAccountHandle getAccountHandle();
     method public int getCallCapabilities();
+    method public int getCallDirection();
     method public android.telecom.CallIdentification getCallIdentification();
     method public int getCallProperties();
     method public java.lang.String getCallerDisplayName();
@@ -42698,6 +42788,9 @@
     field public static final int CAPABILITY_SUPPORT_DEFLECT = 16777216; // 0x1000000
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final int DIRECTION_INCOMING = 0; // 0x0
+    field public static final int DIRECTION_OUTGOING = 1; // 0x1
+    field public static final int DIRECTION_UNKNOWN = -1; // 0xffffffff
     field public static final int PROPERTY_CONFERENCE = 1; // 0x1
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
@@ -44853,6 +44946,7 @@
     method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
     method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
     method public int getEmergencyServiceCategoryBitmask();
+    method public java.util.List<java.lang.String> getEmergencyUrns();
     method public java.lang.String getMnc();
     method public java.lang.String getNumber();
     method public boolean isFromSources(int);
@@ -44906,6 +45000,7 @@
     method public boolean isEnabled();
     method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
     method public void switchToSubscription(int, android.app.PendingIntent);
+    method public void updateSubscriptionNickname(int, java.lang.String, android.app.PendingIntent);
     field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
     field public static final java.lang.String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
@@ -49118,6 +49213,7 @@
     method public float getAxisValue(int);
     method public float getAxisValue(int, int);
     method public int getButtonState();
+    method public int getClassification();
     method public int getDeviceId();
     method public long getDownTime();
     method public int getEdgeFlags();
@@ -49269,6 +49365,9 @@
     field public static final int BUTTON_STYLUS_PRIMARY = 32; // 0x20
     field public static final int BUTTON_STYLUS_SECONDARY = 64; // 0x40
     field public static final int BUTTON_TERTIARY = 4; // 0x4
+    field public static final int CLASSIFICATION_AMBIGUOUS_GESTURE = 1; // 0x1
+    field public static final int CLASSIFICATION_DEEP_PRESS = 2; // 0x2
+    field public static final int CLASSIFICATION_NONE = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.view.MotionEvent> CREATOR;
     field public static final int EDGE_BOTTOM = 2; // 0x2
     field public static final int EDGE_LEFT = 4; // 0x4
@@ -52319,6 +52418,8 @@
     method public final android.view.contentcapture.ContentCaptureSession createContentCaptureSession(android.view.contentcapture.ContentCaptureContext);
     method public final void destroy();
     method public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId();
+    method public android.view.autofill.AutofillId newAutofillId(android.view.autofill.AutofillId, int);
+    method public final android.view.ViewStructure newVirtualViewStructure(android.view.autofill.AutofillId, int);
     method public final void notifyViewAppeared(android.view.ViewStructure);
     method public final void notifyViewDisappeared(android.view.autofill.AutofillId);
     method public final void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index cb1e96a..9a1c804 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -86,11 +86,13 @@
     field public static final java.lang.String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
     field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
+    field public static final java.lang.String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
     field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
     field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
+    field public static final java.lang.String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
     field public static final java.lang.String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
@@ -197,6 +199,7 @@
   }
 
   public static final class R.attr {
+    field public static final int inheritShowWhenLocked = 16844194; // 0x10105a2
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
     field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
@@ -256,6 +259,7 @@
     method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
     method public deprecated boolean isBackgroundVisibleBehind();
     method public deprecated void onBackgroundVisibleBehindChanged(boolean);
+    method public void setInheritShowWhenLocked(boolean);
   }
 
   public static abstract interface Activity.TranslucentConversionListener {
@@ -284,10 +288,11 @@
   }
 
   public class AppOpsManager {
-    method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
-    method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
+    method public void getHistoricalOps(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static java.lang.String[] getOpStrs();
-    method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
+    method public deprecated java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
+    method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, java.lang.String...);
+    method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(java.lang.String[]);
     method public static int opToDefaultMode(java.lang.String);
     method public static java.lang.String opToPermission(java.lang.String);
     method public void setMode(java.lang.String, int, java.lang.String, int);
@@ -343,7 +348,7 @@
     field public static final int UID_STATE_TOP = 1; // 0x1
   }
 
-  public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
+  public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
     method public int describeContents();
     method public long getAccessCount(int);
     method public long getAccessDuration(int);
@@ -353,23 +358,43 @@
     method public long getForegroundAccessCount();
     method public long getForegroundAccessDuration();
     method public long getForegroundRejectCount();
-    method public java.lang.String getOp();
+    method public java.lang.String getOpName();
     method public long getRejectCount(int);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
+  }
+
+  public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getBeginTimeMillis();
+    method public long getEndTimeMillis();
+    method public int getUidCount();
+    method public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
+    method public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
   }
 
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
-    method public int getEntryCount();
+    method public android.app.AppOpsManager.HistoricalOp getOp(java.lang.String);
+    method public android.app.AppOpsManager.HistoricalOp getOpAt(int);
+    method public int getOpCount();
     method public java.lang.String getPackageName();
-    method public int getUid();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
   }
 
+  public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getPackageCount();
+    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(java.lang.String);
+    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
+    method public int getUid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
+  }
+
   public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
     method public int describeContents();
     method public int getDuration();
@@ -537,6 +562,13 @@
     method public void onVrStateChanged(boolean);
   }
 
+  public final class WallpaperColors implements android.os.Parcelable {
+    ctor public WallpaperColors(android.graphics.Color, android.graphics.Color, android.graphics.Color, int);
+    method public int getColorHints();
+    field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
+    field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
+  }
+
   public final class WallpaperInfo implements android.os.Parcelable {
     method public boolean supportsAmbientMode();
   }
@@ -841,6 +873,73 @@
 
 }
 
+package android.app.contentsuggestions {
+
+  public final class ClassificationsRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ClassificationsRequest> CREATOR;
+  }
+
+  public static final class ClassificationsRequest.Builder {
+    ctor public ClassificationsRequest.Builder(java.util.List<android.app.contentsuggestions.ContentSelection>);
+    method public android.app.contentsuggestions.ClassificationsRequest build();
+    method public android.app.contentsuggestions.ClassificationsRequest.Builder setExtras(android.os.Bundle);
+  }
+
+  public final class ContentClassification implements android.os.Parcelable {
+    ctor public ContentClassification(java.lang.String, android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentClassification> CREATOR;
+  }
+
+  public final class ContentSelection implements android.os.Parcelable {
+    ctor public ContentSelection(java.lang.String, android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentSelection> CREATOR;
+  }
+
+  public final class ContentSuggestionsManager {
+    method public void classifyContentSelections(android.app.contentsuggestions.ClassificationsRequest, java.util.concurrent.Executor, android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+    method public void notifyInteraction(java.lang.String, android.os.Bundle);
+    method public void provideContextImage(int, android.os.Bundle);
+    method public void suggestContentSelections(android.app.contentsuggestions.SelectionsRequest, java.util.concurrent.Executor, android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+  }
+
+  public static abstract interface ContentSuggestionsManager.ClassificationsCallback {
+    method public abstract void onContentClassificationsAvailable(int, java.util.List<android.app.contentsuggestions.ContentClassification>);
+  }
+
+  public static abstract interface ContentSuggestionsManager.SelectionsCallback {
+    method public abstract void onContentSelectionsAvailable(int, java.util.List<android.app.contentsuggestions.ContentSelection>);
+  }
+
+  public final class SelectionsRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.Point getInterestPoint();
+    method public int getTaskId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.SelectionsRequest> CREATOR;
+  }
+
+  public static final class SelectionsRequest.Builder {
+    ctor public SelectionsRequest.Builder(int);
+    method public android.app.contentsuggestions.SelectionsRequest build();
+    method public android.app.contentsuggestions.SelectionsRequest.Builder setExtras(android.os.Bundle);
+    method public android.app.contentsuggestions.SelectionsRequest.Builder setInterestPoint(android.graphics.Point);
+  }
+
+}
+
 package android.app.job {
 
   public abstract class JobScheduler {
@@ -849,6 +948,87 @@
 
 }
 
+package android.app.prediction {
+
+  public final class AppPredictionContext implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getPackageName();
+    method public int getPredictedTargetCount();
+    method public java.lang.String getUiSurface();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionContext> CREATOR;
+  }
+
+  public static final class AppPredictionContext.Builder {
+    method public android.app.prediction.AppPredictionContext build();
+    method public android.app.prediction.AppPredictionContext.Builder setExtras(android.os.Bundle);
+    method public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(int);
+    method public android.app.prediction.AppPredictionContext.Builder setUiSurface(java.lang.String);
+  }
+
+  public final class AppPredictionManager {
+    method public android.app.prediction.AppPredictor createAppPredictionSession(android.app.prediction.AppPredictionContext);
+  }
+
+  public final class AppPredictionSessionId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionSessionId> CREATOR;
+  }
+
+  public final class AppPredictor {
+    method public void destroy();
+    method public void notifyAppTargetEvent(android.app.prediction.AppTargetEvent);
+    method public void notifyLocationShown(java.lang.String, java.util.List<android.app.prediction.AppTargetId>);
+    method public void registerPredictionUpdates(java.util.concurrent.Executor, android.app.prediction.AppPredictor.Callback);
+    method public void requestPredictionUpdate();
+    method public void sortTargets(java.util.List<android.app.prediction.AppTarget>, java.util.concurrent.Executor, java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
+    method public void unregisterPredictionUpdates(android.app.prediction.AppPredictor.Callback);
+  }
+
+  public static abstract interface AppPredictor.Callback {
+    method public abstract void onTargetsAvailable(java.util.List<android.app.prediction.AppTarget>);
+  }
+
+  public final class AppTarget implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getClassName();
+    method public android.app.prediction.AppTargetId getId();
+    method public java.lang.String getPackageName();
+    method public int getRank();
+    method public android.content.pm.ShortcutInfo getShortcutInfo();
+    method public android.os.UserHandle getUser();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppTarget> CREATOR;
+  }
+
+  public final class AppTargetEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAction();
+    method public java.lang.String getLaunchLocation();
+    method public android.app.prediction.AppTarget getTarget();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ACTION_DISMISS = 2; // 0x2
+    field public static final int ACTION_LAUNCH = 1; // 0x1
+    field public static final int ACTION_PIN = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
+  }
+
+  public static final class AppTargetEvent.Builder {
+    ctor public AppTargetEvent.Builder(android.app.prediction.AppTarget, int);
+    method public android.app.prediction.AppTargetEvent build();
+    method public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(java.lang.String);
+  }
+
+  public final class AppTargetId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetId> CREATOR;
+  }
+
+}
+
 package android.app.role {
 
   public abstract interface OnRoleHoldersChangedListener {
@@ -1035,7 +1215,9 @@
     method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle);
     method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void startActivityAsUser(android.content.Intent, android.os.UserHandle);
+    field public static final java.lang.String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final java.lang.String BACKUP_SERVICE = "backup";
+    field public static final java.lang.String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
     field public static final java.lang.String EUICC_CARD_SERVICE = "euicc_card";
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
@@ -1103,6 +1285,7 @@
     field public static final java.lang.String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
     field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
     field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
+    field public static final java.lang.String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
     field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
     field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
     field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
@@ -1121,6 +1304,7 @@
 package android.content.pm {
 
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    method public boolean isEncryptionAware();
     method public boolean isInstantApp();
     field public java.lang.String credentialProtectedDataDir;
     field public int targetSandboxVersion;
@@ -1541,6 +1725,10 @@
     field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
   }
 
+  public final class ColorDisplayManager {
+    method public boolean setSaturationLevel(int);
+  }
+
   public final class DisplayManager {
     method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
     method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
@@ -1549,7 +1737,7 @@
     method public android.util.Pair<float[], float[]> getMinimumBrightnessCurve();
     method public android.graphics.Point getStableDisplaySize();
     method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
-    method public void setSaturationLevel(float);
+    method public deprecated void setSaturationLevel(float);
   }
 
 }
@@ -2947,7 +3135,7 @@
     method public void setLocationControllerExtraPackage(java.lang.String);
     method public void setLocationControllerExtraPackageEnabled(boolean);
     method public void setLocationEnabledForUser(boolean, android.os.UserHandle);
-    method public boolean setProviderEnabledForUser(java.lang.String, boolean, android.os.UserHandle);
+    method public deprecated boolean setProviderEnabledForUser(java.lang.String, boolean, android.os.UserHandle);
     method public boolean unregisterGnssBatchedLocationCallback(android.location.BatchedLocationCallback);
   }
 
@@ -3207,6 +3395,22 @@
 
 package android.media.session {
 
+  public final class ControllerCallbackLink implements android.os.Parcelable {
+    ctor public ControllerCallbackLink(android.media.session.ControllerCallbackLink.CallbackStub);
+  }
+
+  public static abstract class ControllerCallbackLink.CallbackStub {
+    ctor public ControllerCallbackLink.CallbackStub();
+    method public void onEvent(java.lang.String, android.os.Bundle);
+    method public void onExtrasChanged(android.os.Bundle);
+    method public void onMetadataChanged(android.media.MediaMetadata);
+    method public void onPlaybackStateChanged(android.media.session.PlaybackState);
+    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
+    method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onSessionDestroyed();
+    method public void onVolumeInfoChanged(android.media.session.MediaController.PlaybackInfo);
+  }
+
   public final class MediaSessionManager {
     method public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, android.os.Handler);
     method public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler);
@@ -5139,6 +5343,24 @@
 
 }
 
+package android.service.appprediction {
+
+  public abstract class AppPredictionService extends android.app.Service {
+    ctor public AppPredictionService();
+    method public abstract void onAppTargetEvent(android.app.prediction.AppPredictionSessionId, android.app.prediction.AppTargetEvent);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onCreatePredictionSession(android.app.prediction.AppPredictionContext, android.app.prediction.AppPredictionSessionId);
+    method public void onDestroyPredictionSession(android.app.prediction.AppPredictionSessionId);
+    method public abstract void onLocationShown(android.app.prediction.AppPredictionSessionId, java.lang.String, java.util.List<android.app.prediction.AppTargetId>);
+    method public abstract void onRequestPredictionUpdate(android.app.prediction.AppPredictionSessionId);
+    method public abstract void onSortAppTargets(android.app.prediction.AppPredictionSessionId, java.util.List<android.app.prediction.AppTarget>, android.os.CancellationSignal, java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
+    method public void onStartPredictionUpdates();
+    method public void onStopPredictionUpdates();
+    method public final void updatePredictions(android.app.prediction.AppPredictionSessionId, java.util.List<android.app.prediction.AppTarget>);
+  }
+
+}
+
 package android.service.autofill {
 
   public abstract class AutofillFieldClassificationService extends android.app.Service {
@@ -5249,6 +5471,7 @@
     method public void onCreateContentCaptureSession(android.view.contentcapture.ContentCaptureContext, android.view.contentcapture.ContentCaptureSessionId);
     method public void onDestroyContentCaptureSession(android.view.contentcapture.ContentCaptureSessionId);
     method public void onDisconnected();
+    method public void onUserDataRemovalRequest(android.view.contentcapture.UserDataRemovalRequest);
     method public final void setActivityContentCaptureEnabled(android.content.ComponentName, boolean);
     method public final void setContentCaptureWhitelist(java.util.List<java.lang.String>, java.util.List<android.content.ComponentName>);
     method public final void setPackageContentCaptureEnabled(java.lang.String, boolean);
@@ -5266,6 +5489,19 @@
 
 }
 
+package android.service.contentsuggestions {
+
+  public abstract class ContentSuggestionsService extends android.app.Service {
+    ctor public ContentSuggestionsService();
+    method public abstract void classifyContentSelections(android.app.contentsuggestions.ClassificationsRequest, android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+    method public abstract void notifyInteraction(java.lang.String, android.os.Bundle);
+    method public abstract void processContextImage(int, android.graphics.Bitmap, android.os.Bundle);
+    method public abstract void suggestContentSelections(android.app.contentsuggestions.SelectionsRequest, android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.contentsuggestions.ContentSuggestionsService";
+  }
+
+}
+
 package android.service.euicc {
 
   public final class DownloadSubscriptionResult implements android.os.Parcelable {
@@ -5428,7 +5664,7 @@
     ctor public NotificationAssistantService();
     method public final void adjustNotification(android.service.notification.Adjustment);
     method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
-    method public void onActionClicked(java.lang.String, android.app.Notification.Action, int);
+    method public void onActionInvoked(java.lang.String, android.app.Notification.Action, int);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onNotificationDirectReplied(java.lang.String);
     method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
@@ -6110,6 +6346,18 @@
     field public static final int WIFI_LOST = 59; // 0x3b
   }
 
+  public final class LteVopsSupportInfo implements android.os.Parcelable {
+    ctor public LteVopsSupportInfo(int, int);
+    method public int describeContents();
+    method public int getEmcBearerSupport();
+    method public int getVopsSupport();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR;
+    field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1
+    field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3
+    field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2
+  }
+
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
     field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
   }
@@ -6376,6 +6624,7 @@
   public class SubscriptionInfo implements android.os.Parcelable {
     method public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
     method public int getCardId();
+    method public int getProfileClass();
   }
 
   public class SubscriptionManager {
@@ -6385,6 +6634,11 @@
     method public void setDefaultDataSubId(int);
     method public void setDefaultSmsSubId(int);
     field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
+    field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
+    field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+    field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+    field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+    field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
     field public static final android.net.Uri VT_ENABLED_CONTENT_URI;
     field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
     field public static final android.net.Uri WFC_MODE_CONTENT_URI;
@@ -6846,6 +7100,7 @@
     method public static int getCallTypeFromVideoState(int);
     method public int getEmergencyCallRouting();
     method public int getEmergencyServiceCategories();
+    method public java.util.List<java.lang.String> getEmergencyUrns();
     method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
     method public int getRestrictCause();
     method public int getServiceType();
@@ -6860,6 +7115,7 @@
     method public void setCallRestrictCause(int);
     method public void setEmergencyCallRouting(int);
     method public void setEmergencyServiceCategories(int);
+    method public void setEmergencyUrns(java.util.List<java.lang.String>);
     method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
     method public void updateCallType(android.telephony.ims.ImsCallProfile);
     method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
diff --git a/api/test-current.txt b/api/test-current.txt
index ae3c1e0..55705b6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -28,6 +28,7 @@
 
   public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
     method public void onMovedToDisplay(int, android.content.res.Configuration);
+    method public void setInheritShowWhenLocked(boolean);
   }
 
   public class ActivityManager {
@@ -89,18 +90,26 @@
   }
 
   public class AppOpsManager {
-    method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
-    method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
+    method public void addHistoricalOps(android.app.AppOpsManager.HistoricalOps);
+    method public void clearHistory();
+    method public void getHistoricalOps(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+    method public void getHistoricalOpsFromDiskRaw(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
     method public static java.lang.String[] getOpStrs();
     method public boolean isOperationActive(int, int, java.lang.String);
+    method public void offsetHistory(long);
     method public static java.lang.String opToPermission(int);
     method public static int permissionToOpCode(java.lang.String);
+    method public void resetHistoryParameters();
+    method public void setHistoryParameters(int, long, int);
     method public void setMode(int, int, java.lang.String, int);
     method public void setUidMode(java.lang.String, int, int);
     method public void startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener);
     method public void stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener);
     method public static int strOpToOp(java.lang.String);
+    field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
+    field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
+    field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
     field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
     field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
     field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
@@ -144,11 +153,18 @@
     field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
     field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms";
     field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
+    field public static final int OP_COARSE_LOCATION = 0; // 0x0
     field public static final int OP_RECORD_AUDIO = 27; // 0x1b
     field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18
+    field public static final int UID_STATE_BACKGROUND = 4; // 0x4
+    field public static final int UID_STATE_CACHED = 5; // 0x5
+    field public static final int UID_STATE_FOREGROUND = 3; // 0x3
+    field public static final int UID_STATE_FOREGROUND_SERVICE = 2; // 0x2
+    field public static final int UID_STATE_PERSISTENT = 0; // 0x0
+    field public static final int UID_STATE_TOP = 1; // 0x1
   }
 
-  public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
+  public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
     method public int describeContents();
     method public long getAccessCount(int);
     method public long getAccessDuration(int);
@@ -158,27 +174,57 @@
     method public long getForegroundAccessCount();
     method public long getForegroundAccessDuration();
     method public long getForegroundRejectCount();
-    method public java.lang.String getOp();
+    method public java.lang.String getOpName();
     method public long getRejectCount(int);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
+  }
+
+  public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
+    ctor public AppOpsManager.HistoricalOps(long, long);
+    method public int describeContents();
+    method public long getBeginTimeMillis();
+    method public long getEndTimeMillis();
+    method public int getUidCount();
+    method public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
+    method public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
+    method public void increaseAccessCount(int, int, java.lang.String, int, long);
+    method public void increaseAccessDuration(int, int, java.lang.String, int, long);
+    method public void increaseRejectCount(int, int, java.lang.String, int, long);
+    method public void offsetBeginAndEndTime(long);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
   }
 
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
-    method public int getEntryCount();
+    method public android.app.AppOpsManager.HistoricalOp getOp(java.lang.String);
+    method public android.app.AppOpsManager.HistoricalOp getOpAt(int);
+    method public int getOpCount();
     method public java.lang.String getPackageName();
-    method public int getUid();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
   }
 
+  public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getPackageCount();
+    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(java.lang.String);
+    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
+    method public int getUid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
+  }
+
   public static abstract interface AppOpsManager.OnOpActiveChangedListener {
     method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean);
   }
 
+  public final class NotificationChannel implements android.os.Parcelable {
+    method public boolean isImportanceLockedByOEM();
+    method public void setImportanceLockedByOEM(boolean);
+  }
+
   public final class NotificationChannelGroup implements android.os.Parcelable {
     method public int getUserLockedFields();
     method public void lockFields(int);
@@ -1235,7 +1281,7 @@
     ctor public NotificationAssistantService();
     method public final void adjustNotification(android.service.notification.Adjustment);
     method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
-    method public void onActionClicked(java.lang.String, android.app.Notification.Action, int);
+    method public void onActionInvoked(java.lang.String, android.app.Notification.Action, int);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onNotificationDirectReplied(java.lang.String);
     method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4918747..4f88127 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -39,6 +39,17 @@
 using android::idmap2::utils::FindFiles;
 
 namespace {
+
+struct InputOverlay {
+  bool operator<(InputOverlay const& rhs) const {
+    return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
+  }
+
+  std::string apk_path;    // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string idmap_path;  // NOLINT(misc-non-private-member-variables-in-classes)
+  int priority;            // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
 std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
                                                        bool recursive, std::ostream& out_error) {
   const auto predicate = [](unsigned char type, const std::string& path) -> bool {
@@ -58,6 +69,7 @@
   }
   return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
 }
+
 }  // namespace
 
 bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
@@ -87,7 +99,7 @@
     return false;
   }
 
-  std::vector<std::string> interesting_apks;
+  std::vector<InputOverlay> interesting_apks;
   for (const std::string& path : *apk_paths) {
     std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
     if (!zip) {
@@ -132,27 +144,29 @@
       continue;
     }
 
+    // Sort the static overlays in ascending priority order
+    std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
+    InputOverlay input{path, idmap_path, priority};
     interesting_apks.insert(
-        std::lower_bound(interesting_apks.begin(), interesting_apks.end(), path), path);
+        std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
   }
 
   std::stringstream stream;
-  for (const auto& apk : interesting_apks) {
-    const std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, apk);
+  for (const auto& overlay : interesting_apks) {
     std::stringstream dev_null;
-    if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}), dev_null) &&
+    if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) &&
         !Create(std::vector<std::string>({
                     "--target-apk-path",
                     target_apk_path,
                     "--overlay-apk-path",
-                    apk,
+                    overlay.apk_path,
                     "--idmap-path",
-                    idmap_path,
+                    overlay.idmap_path,
                 }),
                 out_error)) {
       return false;
     }
-    stream << idmap_path << std::endl;
+    stream <<  overlay.idmap_path << std::endl;
   }
 
   std::cout << stream.str();
diff --git a/cmds/idmap2/static-checks.sh b/cmds/idmap2/static-checks.sh
index 560ccb6..ad9830b 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -70,7 +70,15 @@
 function _cpplint()
 {
     local cpplint="${ANDROID_BUILD_TOP}/tools/repohooks/tools/cpplint.py"
-    $cpplint --quiet $cpp_files
+    local output="$($cpplint --quiet $cpp_files 2>&1 >/dev/null | grep -v \
+        -e 'Found C system header after C++ system header.' \
+        -e 'Unknown NOLINT error category: misc-non-private-member-variables-in-classes' \
+    )"
+    if [[ "$output" ]]; then
+        echo "$output"
+        return 1
+    fi
+    return 0
 }
 
 function _parse_args()
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 6788f7d..d160b73 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -19,12 +19,12 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
-import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
+import android.media.session.ControllerCallbackLink;
 import android.media.session.ISessionController;
-import android.media.session.ISessionControllerCallback;
 import android.media.session.ISessionManager;
 import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession.QueueItem;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.HandlerThread;
@@ -178,13 +178,7 @@
                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
     }
 
-    class ControllerMonitor extends ISessionControllerCallback.Stub {
-        private final ISessionController mController;
-
-        public ControllerMonitor(ISessionController controller) {
-            mController = controller;
-        }
-
+    class ControllerCallbackStub extends ControllerCallbackLink.CallbackStub {
         @Override
         public void onSessionDestroyed() {
             System.out.println("onSessionDestroyed. Enter q to quit.");
@@ -208,25 +202,35 @@
         }
 
         @Override
-        public void onQueueChanged(ParceledListSlice queue) throws RemoteException {
+        public void onQueueChanged(List<QueueItem> queue) {
             System.out.println("onQueueChanged, "
-                    + (queue == null ? "null queue" : " size=" + queue.getList().size()));
+                    + (queue == null ? "null queue" : " size=" + queue.size()));
         }
 
         @Override
-        public void onQueueTitleChanged(CharSequence title) throws RemoteException {
+        public void onQueueTitleChanged(CharSequence title) {
             System.out.println("onQueueTitleChange " + title);
         }
 
         @Override
-        public void onExtrasChanged(Bundle extras) throws RemoteException {
+        public void onExtrasChanged(Bundle extras) {
             System.out.println("onExtrasChanged " + extras);
         }
 
         @Override
-        public void onVolumeInfoChanged(PlaybackInfo info) throws RemoteException {
+        public void onVolumeInfoChanged(PlaybackInfo info) {
             System.out.println("onVolumeInfoChanged " + info);
         }
+    }
+
+    private class ControllerMonitor {
+        private final ISessionController mController;
+        private final ControllerCallbackLink mControllerCallbackLink;
+
+        ControllerMonitor(ISessionController controller) {
+            mController = controller;
+            mControllerCallbackLink = new ControllerCallbackLink(new ControllerCallbackStub());
+        }
 
         void printUsageMessage() {
             try {
@@ -244,7 +248,7 @@
                 @Override
                 protected void onLooperPrepared() {
                     try {
-                        mController.registerCallbackListener(PACKAGE_NAME, ControllerMonitor.this);
+                        mController.registerCallbackListener(PACKAGE_NAME, mControllerCallbackLink);
                     } catch (RemoteException e) {
                         System.out.println("Error registering monitor callback");
                     }
@@ -287,7 +291,7 @@
             } finally {
                 cbThread.getLooper().quit();
                 try {
-                    mController.unregisterCallbackListener(this);
+                    mController.unregisterCallbackListener(mControllerCallbackLink);
                 } catch (Exception e) {
                     // ignoring
                 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index fa3be26..786d8d1 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -25,7 +25,9 @@
 import "frameworks/base/core/proto/android/app/settings_enums.proto";
 import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
+import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
+import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
 import "frameworks/base/core/proto/android/server/location/enums.proto";
 import "frameworks/base/core/proto/android/service/procstats_enum.proto";
@@ -177,6 +179,8 @@
         DocsUIPickResultReported docs_ui_pick_result_reported = 118;
         DocsUISearchModeReported docs_ui_search_mode_reported = 119;
         DocsUISearchTypeReported docs_ui_search_type_reported = 120;
+        DataStallEvent data_stall_event = 121;
+        RescuePartyResetReported rescue_party_reset_reported = 122;
     }
 
     // Pulled events will start at field 10000.
@@ -216,7 +220,7 @@
         NumFingerprints num_fingerprints = 10031;
         DiskIo disk_io = 10032;
         PowerProfile power_profile = 10033;
-        ProcStats proc_stats_pkg_proc = 10034;
+        ProcStatsPkgProc proc_stats_pkg_proc = 10034;
         ProcessCpuTime process_cpu_time = 10035;
         NativeProcessMemoryState native_process_memory_state = 10036;
         CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
@@ -3272,6 +3276,13 @@
     optional ProcessStatsSectionProto proc_stats_section = 1;
 }
 
+/**
+ * Pulled from ProcessStatsService.java
+ */
+message ProcStatsPkgProc {
+    optional ProcessStatsSectionProto proc_stats_section = 1;
+}
+
 message PowerProfileProto {
     optional double cpu_suspend = 1;
 
@@ -3814,3 +3825,37 @@
     // The latency period(in microseconds) it took for this DNS lookup to complete.
     optional int32 latency_micros = 3;
 }
+
+/**
+ * Logs when a data stall event occurs.
+ *
+ * Log from:
+ *     frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+ */
+message DataStallEvent {
+    // Data stall evaluation type.
+    // See frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+    // Refer to the definition of DATA_STALL_EVALUATION_TYPE_*.
+    optional int32 evaluation_type = 1;
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.ProbeResult validation_result = 2;
+    // See definition in data_stall_event.proto.
+    optional android.net.NetworkCapabilitiesProto.Transport network_type = 3;
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.WifiData wifi_info = 4 [(log_mode) = MODE_BYTES];
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.CellularData cell_info = 5 [(log_mode) = MODE_BYTES];
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.DnsEvent dns_event = 6 [(log_mode) = MODE_BYTES];
+}
+
+/*
+ * Logs when RescueParty resets some set of experiment flags.
+ *
+ * Logged from:
+ *     frameworks/base/services/core/java/com/android/server/RescueParty.java
+ */
+message RescuePartyResetReported {
+    // The rescue level of this reset. A value of 0 indicates missing or unknown level information.
+    optional int32 rescue_level = 1;
+}
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index e0e1b72..4d3c5d1 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -490,7 +490,6 @@
 Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
 Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List;
 Landroid/location/ILocationManager;->getNetworkProviderPackage()Ljava/lang/String;
-Landroid/location/ILocationManager;->reportLocation(Landroid/location/Location;Z)V
 Landroid/location/INetInitiatedListener$Stub;-><init>()V
 Landroid/location/INetInitiatedListener;->sendNiResponse(II)Z
 Landroid/location/LocationManager$ListenerTransport;-><init>(Landroid/location/LocationManager;Landroid/location/LocationListener;Landroid/os/Looper;)V
@@ -3566,11 +3565,9 @@
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
 Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
 Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
 Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index f2ad268..35098a0 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -1090,7 +1090,7 @@
          * called) or the service has been disconnected, this method will have
          * no effect and return {@code false}.
          *
-         * @param scale the magnification scale to set, must be >= 1 and <= 5
+         * @param scale the magnification scale to set, must be >= 1 and <= 8
          * @param animate {@code true} to animate from the current scale or
          *                {@code false} to set the scale immediately
          * @return {@code true} on success, {@code false} on failure
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index fdb71bb..347670d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -121,6 +121,7 @@
 import android.view.autofill.AutofillManager.AutofillClient;
 import android.view.autofill.AutofillPopupWindow;
 import android.view.autofill.IAutofillWindowPresenter;
+import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureManager;
 import android.widget.AdapterView;
 import android.widget.Toast;
@@ -1045,14 +1046,19 @@
 
     private void notifyContentCaptureManagerIfNeeded(@ContentCaptureNotificationType int type) {
         final ContentCaptureManager cm = getContentCaptureManager();
-        if (cm == null || !cm.isContentCaptureEnabled()) {
+        if (cm == null) {
             return;
         }
         switch (type) {
             case CONTENT_CAPTURE_START:
                 //TODO(b/111276913): decide whether the InteractionSessionId should be
                 // saved / restored in the activity bundle - probably not
-                cm.onActivityStarted(mToken, getComponentName());
+                int flags = 0;
+                if ((getWindow().getAttributes().flags
+                        & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
+                    flags |= ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE;
+                }
+                cm.onActivityStarted(mToken, getComponentName(), flags);
                 break;
             case CONTENT_CAPTURE_FLUSH:
                 cm.flush();
@@ -8283,6 +8289,33 @@
     }
 
     /**
+     * Specifies whether this {@link Activity} should be shown on top of the lock screen whenever
+     * the lockscreen is up and this activity has another activity behind it with the showWhenLock
+     * attribute set. That is, this activity is only visible on the lock screen if there is another
+     * activity with the showWhenLock attribute visible at the same time on the lock screen. A use
+     * case for this is permission dialogs, that should only be visible on the lock screen if their
+     * requesting activity is also visible. This value can be set as a manifest attribute using
+     * android.R.attr#inheritShowWhenLocked.
+     *
+     * @param inheritShowWhenLocked {@code true} to show the {@link Activity} on top of the lock
+     *                              screen when this activity has another activity behind it with
+     *                              the showWhenLock attribute set; {@code false} otherwise.
+     * @see #setShowWhenLocked(boolean)
+     * See android.R.attr#inheritShowWhenLocked
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public void setInheritShowWhenLocked(boolean inheritShowWhenLocked) {
+        try {
+            ActivityTaskManager.getService().setInheritShowWhenLocked(
+                    mToken, inheritShowWhenLocked);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to call setInheritShowWhenLocked", e);
+        }
+    }
+
+    /**
      * Specifies whether the screen should be turned on when the {@link Activity} is resumed.
      * Normally an activity will be transitioned to the stopped state if it is started while the
      * screen if off, but with this flag set the activity will cause the screen to turn on if the
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9d44e58..c90e404 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -258,8 +258,8 @@
             Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
             boolean sticky, int userId, boolean allowBackgroundActivityStarts);
     public abstract ComponentName startServiceInPackage(int uid, Intent service,
-            String resolvedType, boolean fgRequired, String callingPackage, int userId)
-            throws TransactionTooLargeException;
+            String resolvedType, boolean fgRequired, String callingPackage, int userId,
+            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
 
     public abstract void disconnectActivityFromServices(Object connectionHolder);
     public abstract void cleanUpServices(int userId, ComponentName component, Intent baseIntent);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8faf08a..7767f04 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -271,6 +271,13 @@
     @UnsupportedAppUsage
     final H mH = new H();
     final Executor mExecutor = new HandlerExecutor(mH);
+    /**
+     * Maps from activity token to local record of running activities in this process.
+     *
+     * This variable is readable if the code is running in activity thread or holding {@link
+     * #mResourcesManager}. It's only writable if the code is running in activity thread and holding
+     * {@link #mResourcesManager}.
+     */
     @UnsupportedAppUsage
     final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
     /** The activities to be truly destroyed (not include relaunch). */
@@ -434,6 +441,10 @@
         Configuration newConfig;
         Configuration createdConfig;
         Configuration overrideConfig;
+        // Used to save the last reported configuration from server side so that activity
+        // configuration transactions can always use the latest configuration.
+        @GuardedBy("this")
+        private Configuration mPendingOverrideConfig;
         // Used for consolidating configs before sending on to Activity.
         private Configuration tmpConfig = new Configuration();
         // Callback used for updating activity override config.
@@ -3064,7 +3075,12 @@
             }
             r.setState(ON_CREATE);
 
-            mActivities.put(r.token, r);
+            // updatePendingActivityConfiguration() reads from mActivities to update
+            // ActivityClientRecord which runs in a different thread. Protect modifications to
+            // mActivities to avoid race.
+            synchronized (mResourcesManager) {
+                mActivities.put(r.token, r);
+            }
 
         } catch (SuperNotCalledException e) {
             throw e;
@@ -4639,7 +4655,12 @@
             r.setState(ON_DESTROY);
         }
         schedulePurgeIdler();
-        mActivities.remove(token);
+        // updatePendingActivityConfiguration() reads from mActivities to update
+        // ActivityClientRecord which runs in a different thread. Protect modifications to
+        // mActivities to avoid race.
+        synchronized (mResourcesManager) {
+            mActivities.remove(token);
+        }
         StrictMode.decrementExpectedActivityCount(activityClass);
         return r;
     }
@@ -5382,6 +5403,26 @@
         }
     }
 
+    @Override
+    public void updatePendingActivityConfiguration(IBinder activityToken,
+            Configuration overrideConfig) {
+        final ActivityClientRecord r;
+        synchronized (mResourcesManager) {
+            r = mActivities.get(activityToken);
+        }
+
+        if (r == null) {
+            if (DEBUG_CONFIGURATION) {
+                Slog.w(TAG, "Not found target activity to update its pending config.");
+            }
+            return;
+        }
+
+        synchronized (r) {
+            r.mPendingOverrideConfig = overrideConfig;
+        }
+    }
+
     /**
      * Handle new activity configuration and/or move to a different display.
      * @param activityToken Target activity token.
@@ -5401,6 +5442,24 @@
         final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY
                 && displayId != r.activity.getDisplayId();
 
+        synchronized (r) {
+            if (r.mPendingOverrideConfig != null
+                    && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
+                overrideConfig = r.mPendingOverrideConfig;
+            }
+            r.mPendingOverrideConfig = null;
+        }
+
+        if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
+                && !movedToDifferentDisplay) {
+            if (DEBUG_CONFIGURATION) {
+                Slog.v(TAG, "Activity already handled newer configuration so drop this"
+                        + " transaction. overrideConfig=" + overrideConfig + " r.overrideConfig="
+                        + r.overrideConfig);
+            }
+            return;
+        }
+
         // Perform updates.
         r.overrideConfig = overrideConfig;
         final ViewRootImpl viewRoot = r.activity.mDecor != null
diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl
index 9329fbc..2240302 100644
--- a/core/java/android/app/AppOpsManager.aidl
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -19,5 +19,7 @@
 parcelable AppOpsManager.PackageOps;
 parcelable AppOpsManager.OpEntry;
 
+parcelable AppOpsManager.HistoricalOp;
+parcelable AppOpsManager.HistoricalOps;
 parcelable AppOpsManager.HistoricalPackageOps;
-parcelable AppOpsManager.HistoricalOpEntry;
+parcelable AppOpsManager.HistoricalUidOps;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 78fe002..e155fe2 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -36,26 +36,33 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.ArrayMap;
 
 import com.android.internal.annotations.GuardedBy;
+import android.util.SparseArray;
 import com.android.internal.app.IAppOpsActiveCallback;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsNotedCallback;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * API for interacting with "application operation" tracking.
@@ -106,6 +113,51 @@
 
     static IBinder sToken;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "HISTORICAL_MODE_" }, value = {
+            HISTORICAL_MODE_DISABLED,
+            HISTORICAL_MODE_ENABLED_ACTIVE,
+            HISTORICAL_MODE_ENABLED_PASSIVE
+    })
+    public @interface HistoricalMode {}
+
+    /**
+     * Mode in which app op history is completely disabled.
+     * @hide
+     */
+    @TestApi
+    public static final int HISTORICAL_MODE_DISABLED = 0;
+
+    /**
+     * Mode in which app op history is enabled and app ops performed by apps would
+     * be tracked. This is the mode in which the feature is completely enabled.
+     * @hide
+     */
+    @TestApi
+    public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1;
+
+    /**
+     * Mode in which app op history is enabled but app ops performed by apps would
+     * not be tracked and the only way to add ops to the history is via explicit calls
+     * to dedicated APIs. This mode is useful for testing to allow full control of
+     * the historical content.
+     * @hide
+     */
+    @TestApi
+    public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "MODE_" }, value = {
+            MODE_ALLOWED,
+            MODE_IGNORED,
+            MODE_ERRORED,
+            MODE_DEFAULT,
+            MODE_FOREGROUND
+    })
+    public @interface Mode {}
+
     /**
      * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
      * allowed to perform the given operation.
@@ -159,7 +211,6 @@
             "foreground",   // MODE_FOREGROUND
     };
 
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, prefix = { "UID_STATE_" }, value = {
@@ -173,9 +224,16 @@
     public @interface UidState {}
 
     /**
+     * Invalid UID state.
+     * @hide
+     */
+    public static final int UID_STATE_INVALID = -1;
+
+    /**
      * Metrics about an op when its uid is persistent.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_PERSISTENT = 0;
 
@@ -183,6 +241,7 @@
      * Metrics about an op when its uid is at the top.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_TOP = 1;
 
@@ -190,6 +249,7 @@
      * Metrics about an op when its uid is running a foreground service.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_FOREGROUND_SERVICE = 2;
 
@@ -203,6 +263,7 @@
      * Metrics about an op when its uid is in the foreground for any other reasons.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_FOREGROUND = 3;
 
@@ -210,6 +271,7 @@
      * Metrics about an op when its uid is in the background for any reason.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_BACKGROUND = 4;
 
@@ -217,6 +279,7 @@
      * Metrics about an op when its uid is cached.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_CACHED = 5;
 
@@ -237,7 +300,7 @@
     @UnsupportedAppUsage
     public static final int OP_NONE = -1;
     /** @hide Access to coarse location information. */
-    @UnsupportedAppUsage
+    @TestApi
     public static final int OP_COARSE_LOCATION = 0;
     /** @hide Access to fine location information. */
     @UnsupportedAppUsage
@@ -1645,6 +1708,9 @@
         }
     }
 
+    /** @hide */
+    public static final String KEY_HISTORICAL_OPS = "historical_ops";
+
     /**
      * Retrieve the op switch that controls the given operation.
      * @hide
@@ -1731,7 +1797,7 @@
      * Retrieve the default mode for the operation.
      * @hide
      */
-    public static int opToDefaultMode(int op) {
+    public static @Mode int opToDefaultMode(int op) {
         // STOPSHIP b/118520006: Hardcode the default values once the feature is stable.
         switch (op) {
             // SMS permissions
@@ -1795,7 +1861,7 @@
      * Retrieve the human readable mode.
      * @hide
      */
-    public static String modeToName(int mode) {
+    public static String modeToName(@Mode int mode) {
         if (mode >= 0 && mode < MODE_NAMES.length) {
             return MODE_NAMES[mode];
         }
@@ -1885,7 +1951,7 @@
     @SystemApi
     public static final class OpEntry implements Parcelable {
         private final int mOp;
-        private final int mMode;
+        private final @Mode int mMode;
         private final long[] mTimes;
         private final long[] mRejectTimes;
         private final int mDuration;
@@ -1896,7 +1962,7 @@
         /**
          * @hide
          */
-        public OpEntry(int op, int mode, long time, long rejectTime, int duration,
+        public OpEntry(int op, @Mode int mode, long time, long rejectTime, int duration,
                 int proxyUid, String proxyPackage) {
             mOp = op;
             mMode = mode;
@@ -1913,7 +1979,7 @@
         /**
          * @hide
          */
-        public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+        public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
                 boolean running, int proxyUid, String proxyPackage) {
             mOp = op;
             mMode = mode;
@@ -1930,7 +1996,7 @@
         /**
          * @hide
          */
-        public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+        public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
                 int proxyUid, String proxyPackage) {
             this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage);
         }
@@ -1953,7 +2019,7 @@
         /**
          * Return this entry's current mode, such as {@link #MODE_ALLOWED}.
          */
-        public int getMode() {
+        public @Mode int getMode() {
             return mMode;
         }
 
@@ -2086,41 +2152,774 @@
         };
     }
 
+    /** @hide */
+    public interface HistoricalOpsVisitor {
+        void visitHistoricalOps(@NonNull HistoricalOps ops);
+        void visitHistoricalUidOps(@NonNull HistoricalUidOps ops);
+        void visitHistoricalPackageOps(@NonNull HistoricalPackageOps ops);
+        void visitHistoricalOp(@NonNull HistoricalOp ops);
+    }
+
     /**
-     * This class represents historical app op information about a package. The history
-     * is aggregated information about ops for a certain amount of time such
-     * as the times the op was accessed, the times the op was rejected, the total
-     * duration the app op has been accessed.
+     * This class represents historical app op state of all UIDs for a given time interval.
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final class HistoricalOps implements Parcelable {
+        private long mBeginTimeMillis;
+        private long mEndTimeMillis;
+        private @Nullable SparseArray<HistoricalUidOps> mHistoricalUidOps;
+
+        /** @hide */
+        @TestApi
+        public HistoricalOps(long beginTimeMillis, long endTimeMillis) {
+            Preconditions.checkState(beginTimeMillis <= endTimeMillis);
+            mBeginTimeMillis = beginTimeMillis;
+            mEndTimeMillis = endTimeMillis;
+        }
+
+        /** @hide */
+        public HistoricalOps(@NonNull HistoricalOps other) {
+            mBeginTimeMillis = other.mBeginTimeMillis;
+            mEndTimeMillis = other.mEndTimeMillis;
+            Preconditions.checkState(mBeginTimeMillis <= mEndTimeMillis);
+            if (other.mHistoricalUidOps != null) {
+                final int opCount = other.getUidCount();
+                for (int i = 0; i < opCount; i++) {
+                    final HistoricalUidOps origOps = other.getUidOpsAt(i);
+                    final HistoricalUidOps clonedOps = new HistoricalUidOps(origOps);
+                    if (mHistoricalUidOps == null) {
+                        mHistoricalUidOps = new SparseArray<>(opCount);
+                    }
+                    mHistoricalUidOps.put(clonedOps.getUid(), clonedOps);
+                }
+            }
+        }
+
+        private HistoricalOps(Parcel parcel) {
+            mBeginTimeMillis = parcel.readLong();
+            mEndTimeMillis = parcel.readLong();
+            final int[] uids = parcel.createIntArray();
+            if (!ArrayUtils.isEmpty(uids)) {
+                final ParceledListSlice<HistoricalUidOps> listSlice = parcel.readParcelable(
+                        HistoricalOps.class.getClassLoader());
+                final List<HistoricalUidOps> uidOps = (listSlice != null)
+                        ? listSlice.getList() : null;
+                if (uidOps == null) {
+                    return;
+                }
+                for (int i = 0; i < uids.length; i++) {
+                    if (mHistoricalUidOps == null) {
+                        mHistoricalUidOps = new SparseArray<>();
+                    }
+                    mHistoricalUidOps.put(uids[i], uidOps.get(i));
+                }
+            }
+        }
+
+        /**
+         * Splice a piece from the beginning of these ops.
+         *
+         * @param splicePoint The fraction of the data to be spliced off.
+         *
+         * @hide
+         */
+        public @NonNull HistoricalOps spliceFromBeginning(double splicePoint) {
+            return splice(splicePoint, true);
+        }
+
+        /**
+         * Splice a piece from the end of these ops.
+         *
+         * @param fractionToRemove The fraction of the data to be spliced off.
+         *
+         * @hide
+         */
+        public @NonNull HistoricalOps spliceFromEnd(double fractionToRemove) {
+            return splice(fractionToRemove, false);
+        }
+
+        /**
+         * Splice a piece from the beginning or end of these ops.
+         *
+         * @param fractionToRemove The fraction of the data to be spliced off.
+         * @param beginning Whether to splice off the beginning or the end.
+         *
+         * @return The spliced off part.
+         *
+         * @hide
+         */
+        private @Nullable HistoricalOps splice(double fractionToRemove, boolean beginning) {
+            final long spliceBeginTimeMills;
+            final long spliceEndTimeMills;
+            if (beginning) {
+                spliceBeginTimeMills = mBeginTimeMillis;
+                spliceEndTimeMills = (long) (mBeginTimeMillis
+                        + getDurationMillis() * fractionToRemove);
+                mBeginTimeMillis = spliceEndTimeMills;
+            } else {
+                spliceBeginTimeMills = (long) (mEndTimeMillis
+                        - getDurationMillis() * fractionToRemove);
+                spliceEndTimeMills = mEndTimeMillis;
+                mEndTimeMillis = spliceBeginTimeMills;
+            }
+
+            HistoricalOps splice = null;
+            final int uidCount = getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                final HistoricalUidOps origOps = getUidOpsAt(i);
+                final HistoricalUidOps spliceOps = origOps.splice(fractionToRemove);
+                if (spliceOps != null) {
+                    if (splice == null) {
+                        splice = new HistoricalOps(spliceBeginTimeMills, spliceEndTimeMills);
+                    }
+                    if (splice.mHistoricalUidOps == null) {
+                        splice.mHistoricalUidOps = new SparseArray<>();
+                    }
+                    splice.mHistoricalUidOps.put(spliceOps.getUid(), spliceOps);
+                }
+            }
+            return splice;
+        }
+
+        /**
+         * Merge the passed ops into the current ones. The time interval is a
+         * union of the current and passed in one and the passed in data is
+         * folded into the data of this instance.
+         *
+         * @hide
+         */
+        public void merge(@NonNull HistoricalOps other) {
+            mBeginTimeMillis = Math.min(mBeginTimeMillis, other.mBeginTimeMillis);
+            mEndTimeMillis = Math.max(mEndTimeMillis, other.mEndTimeMillis);
+            final int uidCount = other.getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                final HistoricalUidOps otherUidOps = other.getUidOpsAt(i);
+                final HistoricalUidOps thisUidOps = getUidOps(otherUidOps.getUid());
+                if (thisUidOps != null) {
+                    thisUidOps.merge(otherUidOps);
+                } else {
+                    if (mHistoricalUidOps == null) {
+                        mHistoricalUidOps = new SparseArray<>();
+                    }
+                    mHistoricalUidOps.put(otherUidOps.getUid(), otherUidOps);
+                }
+            }
+        }
+
+        /**
+         * AppPermissionUsage the ops to leave only the data we filter for.
+         *
+         * @param uid Uid to filter for or {@link android.os.Process#INCIDENTD_UID} for all.
+         * @param packageName Package to filter for or null for all.
+         * @param opNames Ops to filter for or null for all.
+         * @param beginTimeMillis The begin time to filter for or {@link Long#MIN_VALUE} for all.
+         * @param endTimeMillis The end time to filter for or {@link Long#MAX_VALUE} for all.
+         *
+         * @hide
+         */
+        public void filter(int uid, @Nullable String packageName, @Nullable String[] opNames,
+                long beginTimeMillis, long endTimeMillis) {
+            final long durationMillis = getDurationMillis();
+            mBeginTimeMillis = Math.max(mBeginTimeMillis, beginTimeMillis);
+            mEndTimeMillis = Math.min(mEndTimeMillis, endTimeMillis);
+            final double scaleFactor = Math.min((double) (endTimeMillis - beginTimeMillis)
+                    / (double) durationMillis, 1);
+            final int uidCount = getUidCount();
+            for (int i = uidCount - 1; i >= 0; i--) {
+                final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
+                if (uid != Process.INVALID_UID && uid != uidOp.getUid()) {
+                    mHistoricalUidOps.removeAt(i);
+                } else {
+                    uidOp.filter(packageName, opNames, scaleFactor);
+                }
+            }
+        }
+
+        /** @hide */
+        public boolean isEmpty() {
+            if (getBeginTimeMillis() >= getEndTimeMillis()) {
+                return true;
+            }
+            final int uidCount = getUidCount();
+            for (int i = uidCount - 1; i >= 0; i--) {
+                final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
+                if (!uidOp.isEmpty()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /** @hide */
+        public long getDurationMillis() {
+            return mEndTimeMillis - mBeginTimeMillis;
+        }
+
+        /** @hide */
+        @TestApi
+        public void increaseAccessCount(int opCode, int uid, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalUidOps(uid).increaseAccessCount(opCode,
+                    packageName, uidState, increment);
+        }
+
+        /** @hide */
+        @TestApi
+        public void increaseRejectCount(int opCode, int uid, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalUidOps(uid).increaseRejectCount(opCode,
+                    packageName, uidState, increment);
+        }
+
+        /** @hide */
+        @TestApi
+        public void increaseAccessDuration(int opCode, int uid, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalUidOps(uid).increaseAccessDuration(opCode,
+                    packageName, uidState, increment);
+        }
+
+        /** @hide */
+        @TestApi
+        public void offsetBeginAndEndTime(long offsetMillis) {
+            mBeginTimeMillis += offsetMillis;
+            mEndTimeMillis += offsetMillis;
+        }
+
+        /** @hide */
+        public void setBeginAndEndTime(long beginTimeMillis, long endTimeMillis) {
+            mBeginTimeMillis = beginTimeMillis;
+            mEndTimeMillis = endTimeMillis;
+        }
+
+        /** @hide */
+        public void setBeginTime(long beginTimeMillis) {
+            mBeginTimeMillis = beginTimeMillis;
+        }
+
+        /** @hide */
+        public void setEndTime(long endTimeMillis) {
+            mEndTimeMillis = endTimeMillis;
+        }
+
+        /**
+         * @return The beginning of the interval in milliseconds since
+         *    epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         */
+        public long getBeginTimeMillis() {
+            return mBeginTimeMillis;
+        }
+
+        /**
+         * @return The end of the interval in milliseconds since
+         *    epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         */
+        public long getEndTimeMillis() {
+            return mEndTimeMillis;
+        }
+
+        /**
+         * Gets number of UIDs with historical ops.
+         *
+         * @return The number of UIDs with historical ops.
+         *
+         * @see #getUidOpsAt(int)
+         */
+        public int getUidCount() {
+            if (mHistoricalUidOps == null) {
+                return 0;
+            }
+            return mHistoricalUidOps.size();
+        }
+
+        /**
+         * Gets the historical UID ops at a given index.
+         *
+         * @param index The index.
+         *
+         * @return The historical UID ops at the given index.
+         *
+         * @see #getUidCount()
+         */
+        public @NonNull HistoricalUidOps getUidOpsAt(int index) {
+            if (mHistoricalUidOps == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mHistoricalUidOps.valueAt(index);
+        }
+
+        /**
+         * Gets the historical UID ops for a given UID.
+         *
+         * @param uid The UID.
+         *
+         * @return The historical ops for the UID.
+         */
+        public @Nullable HistoricalUidOps getUidOps(int uid) {
+            if (mHistoricalUidOps == null) {
+                return null;
+            }
+            return mHistoricalUidOps.get(uid);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeLong(mBeginTimeMillis);
+            parcel.writeLong(mEndTimeMillis);
+            if (mHistoricalUidOps != null) {
+                final int uidCount = mHistoricalUidOps.size();
+                parcel.writeInt(uidCount);
+                for (int i = 0; i < uidCount; i++) {
+                    parcel.writeInt(mHistoricalUidOps.keyAt(i));
+                }
+                final List<HistoricalUidOps> opsList = new ArrayList<>(uidCount);
+                for (int i = 0; i < uidCount; i++) {
+                    opsList.add(mHistoricalUidOps.valueAt(i));
+                }
+                parcel.writeParcelable(new ParceledListSlice<>(opsList), flags);
+            } else {
+                parcel.writeInt(-1);
+            }
+        }
+
+        /**
+         * Accepts a visitor to traverse the ops tree.
+         *
+         * @param visitor The visitor.
+         *
+         * @hide
+         */
+        public void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalOps(this);
+            final int uidCount = getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                getUidOpsAt(i).accept(visitor);
+            }
+        }
+
+        private @NonNull HistoricalUidOps getOrCreateHistoricalUidOps(int uid) {
+            if (mHistoricalUidOps == null) {
+                mHistoricalUidOps = new SparseArray<>();
+            }
+            HistoricalUidOps historicalUidOp = mHistoricalUidOps.get(uid);
+            if (historicalUidOp == null) {
+                historicalUidOp = new HistoricalUidOps(uid);
+                mHistoricalUidOps.put(uid, historicalUidOp);
+            }
+            return historicalUidOp;
+        }
+
+        /**
+         * @return Rounded value up at the 0.5 boundary.
+         *
+         * @hide
+         */
+        public static double round(double value) {
+            final BigDecimal decimalScale = new BigDecimal(value);
+            return decimalScale.setScale(0, RoundingMode.HALF_UP).doubleValue();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalOps other = (HistoricalOps) obj;
+            if (mBeginTimeMillis != other.mBeginTimeMillis) {
+                return false;
+            }
+            if (mEndTimeMillis != other.mEndTimeMillis) {
+                return false;
+            }
+            if (mHistoricalUidOps == null) {
+                if (other.mHistoricalUidOps != null) {
+                    return false;
+                }
+            } else if (!mHistoricalUidOps.equals(other.mHistoricalUidOps)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (mBeginTimeMillis ^ (mBeginTimeMillis >>> 32));
+            result = 31 * result + mHistoricalUidOps.hashCode();
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "[from:"
+                    + mBeginTimeMillis + " to:" + mEndTimeMillis + "]";
+        }
+
+        public static final Creator<HistoricalOps> CREATOR = new Creator<HistoricalOps>() {
+            @Override
+            public @NonNull HistoricalOps createFromParcel(@NonNull Parcel parcel) {
+                return new HistoricalOps(parcel);
+            }
+
+            @Override
+            public @NonNull HistoricalOps[] newArray(int size) {
+                return new HistoricalOps[size];
+            }
+        };
+    }
+
+    /**
+     * This class represents historical app op state for a UID.
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final class HistoricalUidOps implements Parcelable {
+        private final int mUid;
+        private @Nullable ArrayMap<String, HistoricalPackageOps> mHistoricalPackageOps;
+
+        /** @hide */
+        public HistoricalUidOps(int uid) {
+            mUid = uid;
+        }
+
+        private HistoricalUidOps(@NonNull HistoricalUidOps other) {
+            mUid = other.mUid;
+            final int opCount = other.getPackageCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalPackageOps origOps = other.getPackageOpsAt(i);
+                final HistoricalPackageOps cloneOps = new HistoricalPackageOps(origOps);
+                if (mHistoricalPackageOps == null) {
+                    mHistoricalPackageOps = new ArrayMap<>(opCount);
+                }
+                mHistoricalPackageOps.put(cloneOps.getPackageName(), cloneOps);
+            }
+        }
+
+        private HistoricalUidOps(@NonNull Parcel parcel) {
+            // No arg check since we always read from a trusted source.
+            mUid = parcel.readInt();
+            mHistoricalPackageOps = parcel.createTypedArrayMap(HistoricalPackageOps.CREATOR);
+        }
+
+        private @Nullable HistoricalUidOps splice(double fractionToRemove) {
+            HistoricalUidOps splice = null;
+            final int packageCount = getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                final HistoricalPackageOps origOps = getPackageOpsAt(i);
+                final HistoricalPackageOps spliceOps = origOps.splice(fractionToRemove);
+                if (spliceOps != null) {
+                    if (splice == null) {
+                        splice = new HistoricalUidOps(mUid);
+                    }
+                    if (splice.mHistoricalPackageOps == null) {
+                        splice.mHistoricalPackageOps = new ArrayMap<>();
+                    }
+                    splice.mHistoricalPackageOps.put(spliceOps.getPackageName(), spliceOps);
+                }
+            }
+            return splice;
+        }
+
+        private void merge(@NonNull HistoricalUidOps other) {
+            final int packageCount = other.getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                final HistoricalPackageOps otherPackageOps = other.getPackageOpsAt(i);
+                final HistoricalPackageOps thisPackageOps = getPackageOps(
+                        otherPackageOps.getPackageName());
+                if (thisPackageOps != null) {
+                    thisPackageOps.merge(otherPackageOps);
+                } else {
+                    if (mHistoricalPackageOps == null) {
+                        mHistoricalPackageOps = new ArrayMap<>();
+                    }
+                    mHistoricalPackageOps.put(otherPackageOps.getPackageName(), otherPackageOps);
+                }
+            }
+        }
+
+        private void filter(@Nullable String packageName, @Nullable String[] opNames,
+                double fractionToRemove) {
+            final int packageCount = getPackageCount();
+            for (int i = packageCount - 1; i >= 0; i--) {
+                final HistoricalPackageOps packageOps = getPackageOpsAt(i);
+                if (packageName != null && !packageName.equals(packageOps.getPackageName())) {
+                    mHistoricalPackageOps.removeAt(i);
+                } else {
+                    packageOps.filter(opNames, fractionToRemove);
+                }
+            }
+        }
+
+        private boolean isEmpty() {
+            final int packageCount = getPackageCount();
+            for (int i = packageCount - 1; i >= 0; i--) {
+                final HistoricalPackageOps packageOps = mHistoricalPackageOps.valueAt(i);
+                if (!packageOps.isEmpty()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private void increaseAccessCount(int opCode, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalPackageOps(packageName).increaseAccessCount(
+                    opCode, uidState, increment);
+        }
+
+        private void increaseRejectCount(int opCode, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalPackageOps(packageName).increaseRejectCount(
+                    opCode, uidState, increment);
+        }
+
+        private void increaseAccessDuration(int opCode, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalPackageOps(packageName).increaseAccessDuration(
+                    opCode, uidState, increment);
+        }
+
+        /**
+         * @return The UID for which the data is related.
+         */
+        public int getUid() {
+            return mUid;
+        }
+
+        /**
+         * Gets number of packages with historical ops.
+         *
+         * @return The number of packages with historical ops.
+         *
+         * @see #getPackageOpsAt(int)
+         */
+        public int getPackageCount() {
+            if (mHistoricalPackageOps == null) {
+                return 0;
+            }
+            return mHistoricalPackageOps.size();
+        }
+
+        /**
+         * Gets the historical package ops at a given index.
+         *
+         * @param index The index.
+         *
+         * @return The historical package ops at the given index.
+         *
+         * @see #getPackageCount()
+         */
+        public @NonNull HistoricalPackageOps getPackageOpsAt(int index) {
+            if (mHistoricalPackageOps == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mHistoricalPackageOps.valueAt(index);
+        }
+
+        /**
+         * Gets the historical package ops for a given package.
+         *
+         * @param packageName The package.
+         *
+         * @return The historical ops for the package.
+         */
+        public @Nullable HistoricalPackageOps getPackageOps(@NonNull String packageName) {
+            if (mHistoricalPackageOps == null) {
+                return null;
+            }
+            return mHistoricalPackageOps.get(packageName);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeInt(mUid);
+            parcel.writeTypedArrayMap(mHistoricalPackageOps, flags);
+        }
+
+        private void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalUidOps(this);
+            final int packageCount = getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                getPackageOpsAt(i).accept(visitor);
+            }
+        }
+
+        private @NonNull HistoricalPackageOps getOrCreateHistoricalPackageOps(
+                @NonNull String packageName) {
+            if (mHistoricalPackageOps == null) {
+                mHistoricalPackageOps = new ArrayMap<>();
+            }
+            HistoricalPackageOps historicalPackageOp = mHistoricalPackageOps.get(packageName);
+            if (historicalPackageOp == null) {
+                historicalPackageOp = new HistoricalPackageOps(packageName);
+                mHistoricalPackageOps.put(packageName, historicalPackageOp);
+            }
+            return historicalPackageOp;
+        }
+
+
+        public static final Creator<HistoricalUidOps> CREATOR = new Creator<HistoricalUidOps>() {
+            @Override
+            public @NonNull HistoricalUidOps createFromParcel(@NonNull Parcel parcel) {
+                return new HistoricalUidOps(parcel);
+            }
+
+            @Override
+            public @NonNull HistoricalUidOps[] newArray(int size) {
+                return new HistoricalUidOps[size];
+            }
+        };
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalUidOps other = (HistoricalUidOps) obj;
+            if (mUid != other.mUid) {
+                return false;
+            }
+            if (mHistoricalPackageOps == null) {
+                if (other.mHistoricalPackageOps != null) {
+                    return false;
+                }
+            } else if (!mHistoricalPackageOps.equals(other.mHistoricalPackageOps)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mUid;
+            result = 31 * result + (mHistoricalPackageOps != null
+                    ? mHistoricalPackageOps.hashCode() : 0);
+            return result;
+        }
+    }
+
+    /**
+     * This class represents historical app op information about a package.
      *
      * @hide
      */
     @TestApi
     @SystemApi
     public static final class HistoricalPackageOps implements Parcelable {
-        private final int mUid;
         private final @NonNull String mPackageName;
-        private final @NonNull List<HistoricalOpEntry> mEntries;
+        private @Nullable ArrayMap<String, HistoricalOp> mHistoricalOps;
 
-        /**
-         * @hide
-         */
-        public HistoricalPackageOps(int uid, @NonNull String packageName) {
-            mUid = uid;
+        /** @hide */
+        public HistoricalPackageOps(@NonNull String packageName) {
             mPackageName = packageName;
-            mEntries = new ArrayList<>();
         }
 
-        HistoricalPackageOps(@NonNull Parcel parcel) {
-            mUid = parcel.readInt();
+        private HistoricalPackageOps(@NonNull HistoricalPackageOps other) {
+            mPackageName = other.mPackageName;
+            final int opCount = other.getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp origOp = other.getOpAt(i);
+                final HistoricalOp cloneOp = new HistoricalOp(origOp);
+                if (mHistoricalOps == null) {
+                    mHistoricalOps = new ArrayMap<>(opCount);
+                }
+                mHistoricalOps.put(cloneOp.getOpName(), cloneOp);
+            }
+        }
+
+        private HistoricalPackageOps(@NonNull Parcel parcel) {
             mPackageName = parcel.readString();
-            mEntries = parcel.createTypedArrayList(HistoricalOpEntry.CREATOR);
+            mHistoricalOps = parcel.createTypedArrayMap(HistoricalOp.CREATOR);
         }
 
-        /**
-         * @hide
-         */
-        public void addEntry(@NonNull HistoricalOpEntry entry) {
-            mEntries.add(entry);
+        private @Nullable HistoricalPackageOps splice(double fractionToRemove) {
+            HistoricalPackageOps splice = null;
+            final int opCount = getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp origOps = getOpAt(i);
+                final HistoricalOp spliceOps = origOps.splice(fractionToRemove);
+                if (spliceOps != null) {
+                    if (splice == null) {
+                        splice = new HistoricalPackageOps(mPackageName);
+                    }
+                    if (splice.mHistoricalOps == null) {
+                        splice.mHistoricalOps = new ArrayMap<>();
+                    }
+                    splice.mHistoricalOps.put(spliceOps.getOpName(), spliceOps);
+                }
+            }
+            return splice;
+        }
+
+        private void merge(@NonNull HistoricalPackageOps other) {
+            final int opCount = other.getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp otherOp = other.getOpAt(i);
+                final HistoricalOp thisOp = getOp(otherOp.getOpName());
+                if (thisOp != null) {
+                    thisOp.merge(otherOp);
+                } else {
+                    if (mHistoricalOps == null) {
+                        mHistoricalOps = new ArrayMap<>();
+                    }
+                    mHistoricalOps.put(otherOp.getOpName(), otherOp);
+                }
+            }
+        }
+
+        private void filter(@Nullable String[] opNames, double scaleFactor) {
+            final int opCount = getOpCount();
+            for (int i = opCount - 1; i >= 0; i--) {
+                final HistoricalOp op = mHistoricalOps.valueAt(i);
+                if (opNames != null && !ArrayUtils.contains(opNames, op.getOpName())) {
+                    mHistoricalOps.removeAt(i);
+                } else {
+                    op.filter(scaleFactor);
+                }
+            }
+        }
+
+        private boolean isEmpty() {
+            final int opCount = getOpCount();
+            for (int i = opCount - 1; i >= 0; i--) {
+                final HistoricalOp op = mHistoricalOps.valueAt(i);
+                if (!op.isEmpty()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private void increaseAccessCount(int opCode, @UidState int uidState, long increment) {
+            getOrCreateHistoricalOp(opCode).increaseAccessCount(uidState, increment);
+        }
+
+        private void increaseRejectCount(int opCode, @UidState int uidState, long increment) {
+            getOrCreateHistoricalOp(opCode).increaseRejectCount(uidState, increment);
+        }
+
+        private void increaseAccessDuration(int opCode, @UidState int uidState, long increment) {
+            getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, increment);
         }
 
         /**
@@ -2133,36 +2932,33 @@
         }
 
         /**
-         *  Gets the UID which the data represents.
+         * Gets number historical app ops.
          *
-         * @return The UID which the data represents.
+         * @return The number historical app ops.
+         *
+         * @see #getOpAt(int)
          */
-        public int getUid() {
-            return mUid;
+        public int getOpCount() {
+            if (mHistoricalOps == null) {
+                return 0;
+            }
+            return mHistoricalOps.size();
         }
 
         /**
-         * Gets number historical app op entries.
-         *
-         * @return The number historical app op entries.
-         *
-         * @see #getEntryAt(int)
-         */
-        public int getEntryCount() {
-            return mEntries.size();
-        }
-
-        /**
-         * Gets the historical at a given index.
+         * Gets the historical op at a given index.
          *
          * @param index The index to lookup.
          *
-         * @return The entry at the given index.
+         * @return The op at the given index.
          *
-         * @see #getEntryCount()
+         * @see #getOpCount()
          */
-        public @NonNull HistoricalOpEntry getEntryAt(int index) {
-            return mEntries.get(index);
+        public @NonNull HistoricalOp getOpAt(int index) {
+            if (mHistoricalOps == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mHistoricalOps.valueAt(index);
         }
 
         /**
@@ -2172,15 +2968,11 @@
          *
          * @return The historical entry for that op name.
          */
-        public @Nullable HistoricalOpEntry getEntry(@NonNull String opName) {
-            final int entryCount = mEntries.size();
-            for (int i = 0; i < entryCount; i++) {
-                final HistoricalOpEntry entry = mEntries.get(i);
-                if (entry.getOp().equals(opName)) {
-                    return entry;
-                }
+        public @Nullable HistoricalOp getOp(@NonNull String opName) {
+            if (mHistoricalOps == null) {
+                return null;
             }
-            return null;
+            return mHistoricalOps.get(opName);
         }
 
         @Override
@@ -2190,9 +2982,29 @@
 
         @Override
         public void writeToParcel(@NonNull Parcel parcel, int flags) {
-            parcel.writeInt(mUid);
             parcel.writeString(mPackageName);
-            parcel.writeTypedList(mEntries, flags);
+            parcel.writeTypedArrayMap(mHistoricalOps, flags);
+        }
+
+        private void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalPackageOps(this);
+            final int opCount = getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                getOpAt(i).accept(visitor);
+            }
+        }
+
+        private @NonNull HistoricalOp getOrCreateHistoricalOp(int opCode) {
+            if (mHistoricalOps == null) {
+                mHistoricalOps = new ArrayMap<>();
+            }
+            final String opStr = sOpToString[opCode];
+            HistoricalOp op = mHistoricalOps.get(opStr);
+            if (op == null) {
+                op = new HistoricalOp(opCode);
+                mHistoricalOps.put(opStr, op);
+            }
+            return op;
         }
 
         public static final Creator<HistoricalPackageOps> CREATOR =
@@ -2207,49 +3019,177 @@
                 return new HistoricalPackageOps[size];
             }
         };
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalPackageOps other = (HistoricalPackageOps) obj;
+            if (!mPackageName.equals(other.mPackageName)) {
+                return false;
+            }
+            if (mHistoricalOps == null) {
+                if (other.mHistoricalOps != null) {
+                    return false;
+                }
+            } else if (!mHistoricalOps.equals(other.mHistoricalOps)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mPackageName != null ? mPackageName.hashCode() : 0;
+            result = 31 * result + (mHistoricalOps != null ? mHistoricalOps.hashCode() : 0);
+            return result;
+        }
     }
 
     /**
-     * This class represents historical information about an app op. The history
-     * is aggregated information about the op for a certain amount of time such
-     * as the times the op was accessed, the times the op was rejected, the total
-     * duration the app op has been accessed.
+     * This class represents historical information about an app op.
      *
      * @hide
      */
     @TestApi
     @SystemApi
-    public static final class HistoricalOpEntry implements Parcelable {
+    public static final class HistoricalOp implements Parcelable {
         private final int mOp;
-        private final long[] mAccessCount;
-        private final long[] mRejectCount;
-        private final long[] mAccessDuration;
+        private @Nullable long[] mAccessCount;
+        private @Nullable long[] mRejectCount;
+        private @Nullable long[] mAccessDuration;
 
-        /**
-         * @hide
-         */
-        public HistoricalOpEntry(int op) {
+        /** @hide */
+        public HistoricalOp(int op) {
             mOp = op;
             mAccessCount = new long[_NUM_UID_STATE];
             mRejectCount = new long[_NUM_UID_STATE];
             mAccessDuration = new long[_NUM_UID_STATE];
         }
 
-        HistoricalOpEntry(@NonNull Parcel parcel) {
+        private HistoricalOp(@NonNull HistoricalOp other) {
+            mOp = other.mOp;
+            if (other.mAccessCount != null) {
+                System.arraycopy(other.mAccessCount, 0, getOrCreateAccessCount(),
+                        0, other.mAccessCount.length);
+            }
+            if (other.mRejectCount != null) {
+                System.arraycopy(other.mRejectCount, 0, getOrCreateRejectCount(),
+                        0, other.mRejectCount.length);
+            }
+            if (other.mAccessDuration != null) {
+                System.arraycopy(other.mAccessDuration, 0, getOrCreateAccessDuration(),
+                        0, other.mAccessDuration.length);
+            }
+        }
+
+        private HistoricalOp(@NonNull Parcel parcel) {
             mOp = parcel.readInt();
             mAccessCount = parcel.createLongArray();
             mRejectCount = parcel.createLongArray();
             mAccessDuration = parcel.createLongArray();
         }
 
-        /**
-         * @hide
-         */
-        public void addEntry(@UidState int uidState, long accessCount,
-                long rejectCount, long accessDuration) {
-            mAccessCount[uidState] = accessCount;
-            mRejectCount[uidState] = rejectCount;
-            mAccessDuration[uidState] = accessDuration;
+        private void filter(double scaleFactor) {
+            scale(mAccessCount, scaleFactor);
+            scale(mRejectCount, scaleFactor);
+            scale(mAccessDuration, scaleFactor);
+        }
+
+        private boolean isEmpty() {
+            return !hasData(mAccessCount)
+                    && !hasData(mRejectCount)
+                    && !hasData(mAccessDuration);
+        }
+
+        private boolean hasData(@NonNull long[] array) {
+            for (long value : array) {
+                if (value != 0) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private @Nullable HistoricalOp splice(double fractionToRemove) {
+            HistoricalOp splice = null;
+            if (mAccessCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    final long spliceAccessCount = Math.round(
+                            mAccessCount[i] * fractionToRemove);
+                    if (spliceAccessCount > 0) {
+                        if (splice == null) {
+                            splice = new HistoricalOp(mOp);
+                        }
+                        splice.getOrCreateAccessCount()[i] = spliceAccessCount;
+                        mAccessCount[i] -= spliceAccessCount;
+                    }
+                }
+            }
+
+            if (mRejectCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    final long spliceRejectCount = Math.round(
+                            mRejectCount[i] * fractionToRemove);
+
+                    if (spliceRejectCount > 0) {
+                        if (splice == null) {
+                            splice = new HistoricalOp(mOp);
+                        }
+                        splice.getOrCreateRejectCount()[i] = spliceRejectCount;
+                        mRejectCount[i] -= spliceRejectCount;
+                    }
+                }
+            }
+
+            if (mAccessDuration != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    final long spliceAccessDuration =  Math.round(
+                            mAccessDuration[i] * fractionToRemove);
+                    if (spliceAccessDuration > 0) {
+                        if (splice == null) {
+                            splice = new HistoricalOp(mOp);
+                        }
+                        splice.getOrCreateAccessDuration()[i] = spliceAccessDuration;
+                        mAccessDuration[i] -= spliceAccessDuration;
+                    }
+                }
+            }
+            return splice;
+        }
+
+        private void merge(@NonNull HistoricalOp other) {
+            if (other.mAccessCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    getOrCreateAccessCount()[i] += other.mAccessCount[i];
+                }
+            }
+            if (other.mRejectCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    getOrCreateRejectCount()[i] += other.mRejectCount[i];
+                }
+            }
+            if (other.mAccessDuration != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    getOrCreateAccessDuration()[i] += other.mAccessDuration[i];
+                }
+            }
+        }
+
+        private void increaseAccessCount(@UidState int uidState, long increment) {
+            getOrCreateAccessCount()[uidState] += increment;
+        }
+
+        private void increaseRejectCount(@UidState int uidState, long increment) {
+            getOrCreateRejectCount()[uidState] += increment;
+        }
+
+        private void increaseAccessDuration(@UidState int uidState, long increment) {
+            getOrCreateAccessDuration()[uidState] += increment;
         }
 
         /**
@@ -2257,10 +3197,15 @@
          *
          * @return The op name.
          */
-        public @NonNull String getOp() {
+        public @NonNull String getOpName() {
             return sOpToString[mOp];
         }
 
+        /** @hide */
+        public int getOpCode() {
+            return mOp;
+        }
+
         /**
          * Gets the number times the op was accessed (performed) in the foreground.
          *
@@ -2270,6 +3215,9 @@
          * @see #getAccessCount(int)
          */
         public long getForegroundAccessCount() {
+            if (mAccessCount == null) {
+                return 0;
+            }
             return sum(mAccessCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
         }
 
@@ -2282,6 +3230,9 @@
          * @see #getAccessCount(int)
          */
         public long getBackgroundAccessCount() {
+            if (mAccessCount == null) {
+                return 0;
+            }
             return sum(mAccessCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
         }
 
@@ -2299,6 +3250,9 @@
          * @see #getBackgroundAccessCount()
          */
         public long getAccessCount(@UidState int uidState) {
+            if (mAccessCount == null) {
+                return 0;
+            }
             return mAccessCount[uidState];
         }
 
@@ -2311,6 +3265,9 @@
          * @see #getRejectCount(int)
          */
         public long getForegroundRejectCount() {
+            if (mRejectCount == null) {
+                return 0;
+            }
             return sum(mRejectCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
         }
 
@@ -2323,6 +3280,9 @@
          * @see #getRejectCount(int)
          */
         public long getBackgroundRejectCount() {
+            if (mRejectCount == null) {
+                return 0;
+            }
             return sum(mRejectCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
         }
 
@@ -2340,6 +3300,9 @@
          * @see #getBackgroundRejectCount()
          */
         public long getRejectCount(@UidState int uidState) {
+            if (mRejectCount == null) {
+                return 0;
+            }
             return mRejectCount[uidState];
         }
 
@@ -2352,6 +3315,9 @@
          * @see #getAccessDuration(int)
          */
         public long getForegroundAccessDuration() {
+            if (mAccessDuration == null) {
+                return 0;
+            }
             return sum(mAccessDuration, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
         }
 
@@ -2364,6 +3330,9 @@
          * @see #getAccessDuration(int)
          */
         public long getBackgroundAccessDuration() {
+            if (mAccessDuration == null) {
+                return 0;
+            }
             return sum(mAccessDuration, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
         }
 
@@ -2381,6 +3350,9 @@
          * @see #getBackgroundAccessDuration()
          */
         public long getAccessDuration(@UidState int uidState) {
+            if (mAccessDuration == null) {
+                return 0;
+            }
             return mAccessDuration[uidState];
         }
 
@@ -2397,34 +3369,29 @@
             parcel.writeLongArray(mAccessDuration);
         }
 
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-            if (other == null || getClass() != other.getClass()) {
-                return false;
-            }
-            final HistoricalOpEntry otherInstance = (HistoricalOpEntry) other;
-            if (mOp != otherInstance.mOp) {
-                return false;
-            }
-            if (!Arrays.equals(mAccessCount, otherInstance.mAccessCount)) {
-                return false;
-            }
-            if (!Arrays.equals(mRejectCount, otherInstance.mRejectCount)) {
-                return false;
-            }
-            return Arrays.equals(mAccessDuration, otherInstance.mAccessDuration);
+        private void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalOp(this);
         }
 
-        @Override
-        public int hashCode() {
-            int result = mOp;
-            result = 31 * result + Arrays.hashCode(mAccessCount);
-            result = 31 * result + Arrays.hashCode(mRejectCount);
-            result = 31 * result + Arrays.hashCode(mAccessDuration);
-            return result;
+        private @NonNull long[] getOrCreateAccessCount() {
+            if (mAccessCount == null) {
+                mAccessCount = new long[_NUM_UID_STATE];
+            }
+            return mAccessCount;
+        }
+
+        private @NonNull long[] getOrCreateRejectCount() {
+            if (mRejectCount == null) {
+                mRejectCount = new long[_NUM_UID_STATE];
+            }
+            return mRejectCount;
+        }
+
+        private @NonNull long[] getOrCreateAccessDuration() {
+            if (mAccessDuration == null) {
+                mAccessDuration = new long[_NUM_UID_STATE];
+            }
+            return mAccessDuration;
         }
 
         /**
@@ -2444,17 +3411,62 @@
             return totalCount;
         }
 
-        public static final Creator<HistoricalOpEntry> CREATOR = new Creator<HistoricalOpEntry>() {
+        /**
+         * Multiplies the entries in the array with the passed in scale factor and
+         * rounds the result at up 0.5 boundary.
+         *
+         * @param data The data to scale.
+         * @param scaleFactor The scale factor.
+         */
+        private static void scale(@NonNull long[] data, double scaleFactor) {
+            if (data != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    data[i] = (long) HistoricalOps.round((double) data[i] * scaleFactor);
+                }
+            }
+        }
+
+        public static final Creator<HistoricalOp> CREATOR = new Creator<HistoricalOp>() {
             @Override
-            public @NonNull HistoricalOpEntry createFromParcel(@NonNull Parcel source) {
-                return new HistoricalOpEntry(source);
+            public @NonNull HistoricalOp createFromParcel(@NonNull Parcel source) {
+                return new HistoricalOp(source);
             }
 
             @Override
-            public @NonNull HistoricalOpEntry[] newArray(int size) {
-                return new HistoricalOpEntry[size];
+            public @NonNull HistoricalOp[] newArray(int size) {
+                return new HistoricalOp[size];
             }
         };
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalOp other = (HistoricalOp) obj;
+            if (mOp != other.mOp) {
+                return false;
+            }
+            if (!Arrays.equals(mAccessCount, other.mAccessCount)) {
+                return false;
+            }
+            if (!Arrays.equals(mRejectCount, other.mRejectCount)) {
+                return false;
+            }
+            return Arrays.equals(mAccessDuration, other.mAccessDuration);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mOp;
+            result = 31 * result + Arrays.hashCode(mAccessCount);
+            result = 31 * result + Arrays.hashCode(mRejectCount);
+            result = 31 * result + Arrays.hashCode(mAccessDuration);
+            return result;
+        }
     }
 
     /**
@@ -2520,6 +3532,24 @@
      * @param ops The set of operations you are interested in, or null if you want all of them.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+    public @NonNull List<AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[] ops) {
+        final int opCount = ops.length;
+        final int[] opCodes = new int[opCount];
+        for (int i = 0; i < opCount; i++) {
+            opCodes[i] = sOpStrToOp.get(ops[i]);
+        }
+        final List<AppOpsManager.PackageOps> result = getPackagesForOps(opCodes);
+        return (result != null) ? result : Collections.emptyList();
+    }
+
+    /**
+     * Retrieve current operation state for all applications.
+     *
+     * @param ops The set of operations you are interested in, or null if you want all of them.
+     * @hide
+     */
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
     @UnsupportedAppUsage
     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
@@ -2536,11 +3566,17 @@
      * @param uid The uid of the application of interest.
      * @param packageName The name of the application of interest.
      * @param ops The set of operations you are interested in, or null if you want all of them.
+     *
+     * @deprecated The int op codes are not stable and you should use the string based op
+     * names which are stable and namespaced. Use
+     * {@link #getOpsForPackage(int, String, String...)})}.
+     *
      * @hide
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
+    public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
         try {
             return mService.getOpsForPackage(uid, packageName, ops);
         } catch (RemoteException e) {
@@ -2549,7 +3585,49 @@
     }
 
     /**
-     * Retrieve historical app op stats for a package.
+     * Retrieve current operation state for one application. The UID and the
+     * package must match.
+     *
+     * @param uid The uid of the application of interest.
+     * @param packageName The name of the application of interest.
+     * @param ops The set of operations you are interested in, or null if you want all of them.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+    public @NonNull List<AppOpsManager.PackageOps> getOpsForPackage(int uid,
+            @NonNull String packageName, @Nullable String... ops) {
+        int[] opCodes = null;
+        if (ops != null) {
+            opCodes = new int[ops.length];
+            for (int i = 0; i < ops.length; i++) {
+                opCodes[i] = strOpToOp(ops[i]);
+            }
+        }
+        try {
+            final List<PackageOps> result = mService.getOpsForPackage(uid, packageName, opCodes);
+            if (result == null) {
+                return Collections.emptyList();
+            }
+            return result;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieve historical app op stats for a period.
+     *
+     * <p>Historical data can be obtained
+     * for a specific package by specifying the <code>packageName</code> argument,
+     * for a specific UID if specifying the <code>uid</code> argument, for a
+     * specific package in a UID by specifying the <code>packageName</code>
+     * and the <code>uid</code> arguments, for all packages by passing
+     * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
+     *  <code>uid</code> and <code>packageName</code> arguments, respectively.
+     *  Similarly, you can specify the <code>opNames</code> argument to get
+     *  data only for these ops or <code>null</code> for all ops.
      *
      * @param uid The UID to query for.
      * @param packageName The package to query for.
@@ -2558,10 +3636,12 @@
      *     negative.
      * @param endTimeMillis The end of the interval in milliseconds since
      *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
-     *     {@code beginTimeMillis}.
+     *     {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
+     *     history including ops that happen while this call is in flight.
      * @param opNames The ops to query for. Pass {@code null} for all ops.
-     *
-     * @return The historical ops or {@code null} if there are no ops for this package.
+     * @param executor Executor on which to run the callback. If <code>null</code>
+     *     the callback is executed on the default executor running on the main thread.
+     * @param callback Callback on which to deliver the result.
      *
      * @throws IllegalArgumentException If any of the argument contracts is violated.
      *
@@ -2570,47 +3650,78 @@
     @TestApi
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public @Nullable HistoricalPackageOps getHistoricalPackagesOps(
-            int uid, @NonNull String packageName, @Nullable String[] opNames,
-            long beginTimeMillis, long endTimeMillis) {
+    public void getHistoricalOps(int uid, @Nullable String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
+        Preconditions.checkNotNull(executor, "executor cannot be null");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            return mService.getHistoricalPackagesOps(uid, packageName, opNames,
-                    beginTimeMillis, endTimeMillis);
+            mService.getHistoricalOps(uid, packageName, opNames, beginTimeMillis, endTimeMillis,
+                    new RemoteCallback((result) -> {
+                final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> callback.accept(ops));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Retrieve historical app op stats for all packages.
+     * Retrieve historical app op stats for a period.
      *
+     * <p>Historical data can be obtained
+     * for a specific package by specifying the <code>packageName</code> argument,
+     * for a specific UID if specifying the <code>uid</code> argument, for a
+     * specific package in a UID by specifying the <code>packageName</code>
+     * and the <code>uid</code> arguments, for all packages by passing
+     * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
+     *  <code>uid</code> and <code>packageName</code> arguments, respectively.
+     *  Similarly, you can specify the <code>opNames</code> argument to get
+     *  data only for these ops or <code>null</code> for all ops.
+     *  <p>
+     *  This method queries only the on disk state and the returned ops are raw,
+     *  which is their times are relative to the history start as opposed to the
+     *  epoch start.
+     *
+     * @param uid The UID to query for.
+     * @param packageName The package to query for.
      * @param beginTimeMillis The beginning of the interval in milliseconds since
-     *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
-     *     negative.
+     *      history start. History time grows as one goes into the past.
      * @param endTimeMillis The end of the interval in milliseconds since
-     *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
+     *      history start. History time grows as one goes into the past. Must be after
      *     {@code beginTimeMillis}.
      * @param opNames The ops to query for. Pass {@code null} for all ops.
-     *
-     * @return The historical ops or an empty list if there are no ops for any package.
+     * @param executor Executor on which to run the callback. If <code>null</code>
+     *     the callback is executed on the default executor running on the main thread.
+     * @param callback Callback on which to deliver the result.
      *
      * @throws IllegalArgumentException If any of the argument contracts is violated.
      *
      * @hide
      */
     @TestApi
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public @NonNull List<HistoricalPackageOps> getAllHistoricPackagesOps(
-            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis) {
+    public void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
+        Preconditions.checkNotNull(executor, "executor cannot be null");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            @SuppressWarnings("unchecked")
-            final ParceledListSlice<HistoricalPackageOps> payload =
-                    mService.getAllHistoricalPackagesOps(opNames, beginTimeMillis, endTimeMillis);
-            if (payload != null) {
-                return payload.getList();
-            }
-            return Collections.emptyList();
+            mService.getHistoricalOpsFromDiskRaw(uid, packageName, opNames, beginTimeMillis,
+                    endTimeMillis, new RemoteCallback((result) -> {
+               final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> callback.accept(ops));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2627,7 +3738,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setUidMode(int code, int uid, int mode) {
+    public void setUidMode(int code, int uid, @Mode int mode) {
         try {
             mService.setUidMode(code, uid, mode);
         } catch (RemoteException e) {
@@ -2648,7 +3759,7 @@
     @SystemApi
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setUidMode(String appOp, int uid, int mode) {
+    public void setUidMode(String appOp, int uid, @Mode int mode) {
         try {
             mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
         } catch (RemoteException e) {
@@ -2680,7 +3791,7 @@
     /** @hide */
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setMode(int code, int uid, String packageName, int mode) {
+    public void setMode(int code, int uid, String packageName, @Mode int mode) {
         try {
             mService.setMode(code, uid, packageName, mode);
         } catch (RemoteException e) {
@@ -2701,7 +3812,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setMode(String op, int uid, String packageName, int mode) {
+    public void setMode(String op, int uid, String packageName, @Mode int mode) {
         try {
             mService.setMode(strOpToOp(op), uid, packageName, mode);
         } catch (RemoteException e) {
@@ -2722,7 +3833,7 @@
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
     @UnsupportedAppUsage
-    public void setRestriction(int code, @AttributeUsage int usage, int mode,
+    public void setRestriction(int code, @AttributeUsage int usage, @Mode int mode,
             String[] exceptionPackages) {
         try {
             final int uid = Binder.getCallingUid();
@@ -3507,6 +4618,104 @@
     }
 
     /**
+     * Configures the app ops persistence for testing.
+     *
+     * @param mode The mode in which the historical registry operates.
+     * @param baseSnapshotInterval The base interval on which we would be persisting a snapshot of
+     *   the historical data. The history is recursive where every subsequent step encompasses
+     *   {@code compressionStep} longer interval with {@code compressionStep} distance between
+     *    snapshots.
+     * @param compressionStep The compression step in every iteration.
+     *
+     * @see #HISTORICAL_MODE_DISABLED
+     * @see #HISTORICAL_MODE_ENABLED_ACTIVE
+     * @see #HISTORICAL_MODE_ENABLED_PASSIVE
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void setHistoryParameters(@HistoricalMode int mode, long baseSnapshotInterval,
+            int compressionStep) {
+        try {
+            mService.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Offsets the history by the given duration.
+     *
+     * @param offsetMillis The offset duration.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void offsetHistory(long offsetMillis) {
+        try {
+            mService.offsetHistory(offsetMillis);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Adds ops to the history directly. This could be useful for testing especially
+     * when the historical registry operates in {@link #HISTORICAL_MODE_ENABLED_PASSIVE}
+     * mode.
+     *
+     * @param ops The ops to add to the history.
+     *
+     * @see #setHistoryParameters(int, long, int)
+     * @see #HISTORICAL_MODE_ENABLED_PASSIVE
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void addHistoricalOps(@NonNull HistoricalOps ops) {
+        try {
+            mService.addHistoricalOps(ops);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Resets the app ops persistence for testing.
+     *
+     * @see #setHistoryParameters(int, long, int)
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void resetHistoryParameters() {
+        try {
+            mService.resetHistoryParameters();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Clears all app ops history.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void clearHistory() {
+        try {
+            mService.clearHistory();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns all supported operation names.
      * @hide
      */
@@ -3538,4 +4747,64 @@
         }
         return time;
     }
+
+    /** @hide */
+    public static String uidStateToString(@UidState int uidState) {
+        switch (uidState) {
+            case UID_STATE_PERSISTENT: {
+                return "UID_STATE_PERSISTENT";
+            }
+            case UID_STATE_TOP: {
+                return "UID_STATE_TOP";
+            }
+            case UID_STATE_FOREGROUND_SERVICE: {
+                return "UID_STATE_FOREGROUND_SERVICE";
+            }
+            case UID_STATE_FOREGROUND: {
+                return "UID_STATE_FOREGROUND";
+            }
+            case UID_STATE_BACKGROUND: {
+                return "UID_STATE_BACKGROUND";
+            }
+            case UID_STATE_CACHED: {
+                return "UID_STATE_CACHED";
+            }
+            default: {
+                return "UNKNOWN";
+            }
+        }
+    }
+
+    /** @hide */
+    public static int parseHistoricalMode(@NonNull String mode) {
+        switch (mode) {
+            case "HISTORICAL_MODE_ENABLED_ACTIVE": {
+                return HISTORICAL_MODE_ENABLED_ACTIVE;
+            }
+            case "HISTORICAL_MODE_ENABLED_PASSIVE": {
+                return HISTORICAL_MODE_ENABLED_PASSIVE;
+            }
+            default: {
+                return HISTORICAL_MODE_DISABLED;
+            }
+        }
+    }
+
+    /** @hide */
+    public static String historicalModeToString(@HistoricalMode int mode) {
+        switch (mode) {
+            case HISTORICAL_MODE_DISABLED: {
+                return "HISTORICAL_MODE_DISABLED";
+            }
+            case HISTORICAL_MODE_ENABLED_ACTIVE: {
+                return "HISTORICAL_MODE_ENABLED_ACTIVE";
+            }
+            case HISTORICAL_MODE_ENABLED_PASSIVE: {
+                return "HISTORICAL_MODE_ENABLED_PASSIVE";
+            }
+            default: {
+                return "UNKNOWN";
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index b5295d1..07dbb6b 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -124,6 +124,10 @@
     /** Restart the activity after it was stopped. */
     public abstract void performRestartActivity(IBinder token, boolean start);
 
+    /** Set pending activity configuration in case it will be updated by other transaction item. */
+    public abstract void updatePendingActivityConfiguration(IBinder activityToken,
+            Configuration overrideConfig);
+
     /** Deliver activity (override) configuration change. */
     public abstract void handleActivityConfigurationChanged(IBinder activityToken,
             Configuration overrideConfig, int displayId);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index dd87dc3..cc6c999 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -419,6 +419,7 @@
     void updateLockTaskFeatures(int userId, int flags);
 
     void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
+    void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
     void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
 
     /**
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 41ceaaf..950e9aa 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -19,6 +19,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.NotificationManager.Importance;
 import android.content.ContentResolver;
@@ -168,6 +169,7 @@
     // If this is a blockable system notification channel.
     private boolean mBlockableSystem = false;
     private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+    private boolean mImportanceLockedByOEM;
 
     /**
      * Creates a notification channel.
@@ -230,6 +232,7 @@
         mLightColor = in.readInt();
         mBlockableSystem = in.readBoolean();
         mAllowAppOverlay = in.readBoolean();
+        mImportanceLockedByOEM = in.readBoolean();
     }
 
     @Override
@@ -283,6 +286,7 @@
         dest.writeInt(mLightColor);
         dest.writeBoolean(mBlockableSystem);
         dest.writeBoolean(mAllowAppOverlay);
+        dest.writeBoolean(mImportanceLockedByOEM);
     }
 
     /**
@@ -649,6 +653,22 @@
     }
 
     /**
+     * @hide
+     */
+    @TestApi
+    public void setImportanceLockedByOEM(boolean locked) {
+        mImportanceLockedByOEM = locked;
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public boolean isImportanceLockedByOEM() {
+        return mImportanceLockedByOEM;
+    }
+
+    /**
      * Returns whether the user has chosen the importance of this channel, either to affirm the
      * initial selection from the app, or changed it to be higher or lower.
      * @see #getImportance()
@@ -952,25 +972,26 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         NotificationChannel that = (NotificationChannel) o;
-        return getImportance() == that.getImportance() &&
-                mBypassDnd == that.mBypassDnd &&
-                getLockscreenVisibility() == that.getLockscreenVisibility() &&
-                mLights == that.mLights &&
-                getLightColor() == that.getLightColor() &&
-                getUserLockedFields() == that.getUserLockedFields() &&
-                isFgServiceShown() == that.isFgServiceShown() &&
-                mVibrationEnabled == that.mVibrationEnabled &&
-                mShowBadge == that.mShowBadge &&
-                isDeleted() == that.isDeleted() &&
-                isBlockableSystem() == that.isBlockableSystem() &&
-                mAllowAppOverlay == that.mAllowAppOverlay &&
-                Objects.equals(getId(), that.getId()) &&
-                Objects.equals(getName(), that.getName()) &&
-                Objects.equals(mDesc, that.mDesc) &&
-                Objects.equals(getSound(), that.getSound()) &&
-                Arrays.equals(mVibration, that.mVibration) &&
-                Objects.equals(getGroup(), that.getGroup()) &&
-                Objects.equals(getAudioAttributes(), that.getAudioAttributes());
+        return getImportance() == that.getImportance()
+                && mBypassDnd == that.mBypassDnd
+                && getLockscreenVisibility() == that.getLockscreenVisibility()
+                && mLights == that.mLights
+                && getLightColor() == that.getLightColor()
+                && getUserLockedFields() == that.getUserLockedFields()
+                && isFgServiceShown() == that.isFgServiceShown()
+                && mVibrationEnabled == that.mVibrationEnabled
+                && mShowBadge == that.mShowBadge
+                && isDeleted() == that.isDeleted()
+                && isBlockableSystem() == that.isBlockableSystem()
+                && mAllowAppOverlay == that.mAllowAppOverlay
+                && Objects.equals(getId(), that.getId())
+                && Objects.equals(getName(), that.getName())
+                && Objects.equals(mDesc, that.mDesc)
+                && Objects.equals(getSound(), that.getSound())
+                && Arrays.equals(mVibration, that.mVibration)
+                && Objects.equals(getGroup(), that.getGroup())
+                && Objects.equals(getAudioAttributes(), that.getAudioAttributes())
+                && mImportanceLockedByOEM == that.mImportanceLockedByOEM;
     }
 
     @Override
@@ -979,7 +1000,8 @@
                 getLockscreenVisibility(), getSound(), mLights, getLightColor(),
                 getUserLockedFields(),
                 isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
-                getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay);
+                getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay,
+                mImportanceLockedByOEM);
         result = 31 * result + Arrays.hashCode(mVibration);
         return result;
     }
@@ -1007,6 +1029,7 @@
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
                 + ", mAllowAppOverlay=" + mAllowAppOverlay
+                + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
                 + '}';
         pw.println(prefix + output);
     }
@@ -1033,6 +1056,7 @@
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
                 + ", mAllowAppOverlay=" + mAllowAppOverlay
+                + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
                 + '}';
     }
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 9ddf4bd..d827f6c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -21,8 +21,11 @@
 import android.app.ContextImpl.ServiceInitializationState;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IContentSuggestionsManager;
 import android.app.job.IJobScheduler;
 import android.app.job.JobScheduler;
+import android.app.prediction.AppPredictionManager;
 import android.app.role.RoleManager;
 import android.app.slice.SliceManager;
 import android.app.timedetector.TimeDetector;
@@ -95,8 +98,10 @@
 import android.net.EthernetManager;
 import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
+import android.net.IIpMemoryStore;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.IpMemoryStore;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
@@ -120,6 +125,7 @@
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
+import android.os.BugreportManager;
 import android.os.Build;
 import android.os.DeviceIdleManager;
 import android.os.DropBoxManager;
@@ -127,6 +133,7 @@
 import android.os.IBatteryPropertiesRegistrar;
 import android.os.IBinder;
 import android.os.IDeviceIdleController;
+import android.os.IDumpstate;
 import android.os.IHardwarePropertiesManager;
 import android.os.IPowerManager;
 import android.os.IRecoverySystem;
@@ -321,10 +328,21 @@
 
         registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class,
                 new StaticServiceFetcher<NetworkStack>() {
-                @Override
-                public NetworkStack createService() {
-                    return new NetworkStack();
-                }});
+                    @Override
+                    public NetworkStack createService() {
+                        return new NetworkStack();
+                    }});
+
+        registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class,
+                new CachedServiceFetcher<IpMemoryStore>() {
+                    @Override
+                    public IpMemoryStore createService(final ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.IP_MEMORY_STORE_SERVICE);
+                        IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b);
+                        return new IpMemoryStore(ctx, service);
+                    }});
 
         registerService(Context.IPSEC_SERVICE, IpSecManager.class,
                 new CachedServiceFetcher<IpSecManager>() {
@@ -1069,6 +1087,16 @@
                 return new IncidentManager(ctx);
             }});
 
+        registerService(Context.BUGREPORT_SERVICE, BugreportManager.class,
+                new CachedServiceFetcher<BugreportManager>() {
+                    @Override
+                    public BugreportManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(Context.BUGREPORT_SERVICE);
+                        return new BugreportManager(ctx.getOuterContext(),
+                                IDumpstate.Stub.asInterface(b));
+                    }});
+
         registerService(Context.AUTOFILL_MANAGER_SERVICE, AutofillManager.class,
                 new CachedServiceFetcher<AutofillManager>() {
             @Override
@@ -1095,6 +1123,29 @@
                 return null;
             }});
 
+        registerService(Context.APP_PREDICTION_SERVICE, AppPredictionManager.class,
+                new CachedServiceFetcher<AppPredictionManager>() {
+            @Override
+            public AppPredictionManager createService(ContextImpl ctx)
+                    throws ServiceNotFoundException {
+                return new AppPredictionManager(ctx);
+            }
+        });
+
+        registerService(Context.CONTENT_SUGGESTIONS_SERVICE,
+                ContentSuggestionsManager.class,
+                new CachedServiceFetcher<ContentSuggestionsManager>() {
+                    @Override
+                    public ContentSuggestionsManager createService(ContextImpl ctx) {
+                        // No throw as this is an optional service
+                        IBinder b = ServiceManager.getService(
+                                Context.CONTENT_SUGGESTIONS_SERVICE);
+                        IContentSuggestionsManager service =
+                                IContentSuggestionsManager.Stub.asInterface(b);
+                        return new ContentSuggestionsManager(service);
+                    }
+                });
+
         registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
             @Override
             public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index ace814a..38a98d3c8 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -56,6 +56,7 @@
      * eg. A launcher may set its text color to black if this flag is specified.
      * @hide
      */
+    @SystemApi
     public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
 
     /**
@@ -64,6 +65,7 @@
      * eg. A launcher may set its drawer color to black if this flag is specified.
      * @hide
      */
+    @SystemApi
     public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
 
     /**
@@ -234,7 +236,7 @@
      * @see WallpaperColors#fromDrawable(Drawable)
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public WallpaperColors(@NonNull Color primaryColor, @Nullable Color secondaryColor,
             @Nullable Color tertiaryColor, int colorHints) {
 
@@ -349,7 +351,7 @@
      * @return True if dark text is supported.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public int getColorHints() {
         return mColorHints;
     }
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 2990b57..e0a15a5 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityThread.isSystem;
 import static android.app.WindowConfigurationProto.ACTIVITY_TYPE;
 import static android.app.WindowConfigurationProto.APP_BOUNDS;
+import static android.app.WindowConfigurationProto.BOUNDS;
 import static android.app.WindowConfigurationProto.WINDOWING_MODE;
 import static android.view.Surface.rotationToString;
 
@@ -585,6 +586,9 @@
         }
         protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
         protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
+        if (mBounds != null) {
+            mBounds.writeToProto(protoOutputStream, BOUNDS);
+        }
         protoOutputStream.end(token);
     }
 
@@ -606,6 +610,10 @@
                         mAppBounds = new Rect();
                         mAppBounds.readFromProto(proto, APP_BOUNDS);
                         break;
+                    case (int) BOUNDS:
+                        mBounds = new Rect();
+                        mBounds.readFromProto(proto, BOUNDS);
+                        break;
                     case (int) WINDOWING_MODE:
                         mWindowingMode = proto.readInt(WINDOWING_MODE);
                         break;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7da67d9..9247486 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6815,8 +6815,12 @@
     }
 
     /**
-     * Returns the list of input methods permitted by the device or profiles
-     * owners of the current user.  (*Not* calling user, due to a limitation in InputMethodManager.)
+     * Returns the list of input methods permitted by the device or profiles owners.
+     *
+     * <p>On {@link android.os.Build.VERSION_CODES#Q} and later devices, this method returns the
+     * result for the calling user.</p>
+     *
+     * <p>On Android P and prior devices, this method returns the result for the current user.</p>
      *
      * <p>Null means all input methods are allowed, if a non-null list is returned
      * it will contain the intersection of the permitted lists for any device or profile
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index cc4d4b1a..7d03f00 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1699,7 +1699,8 @@
 
         @Override
         public void setVisibility(int visibility) {
-            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
+            mNode.mFlags = (mNode.mFlags & ~ViewNode.FLAGS_VISIBILITY_MASK)
+                    | (visibility & ViewNode.FLAGS_VISIBILITY_MASK);
         }
 
         @Override
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl b/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl
new file mode 100644
index 0000000..a66413b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.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.app.contentsuggestions;
+
+parcelable ClassificationsRequest;
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.java b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
new file mode 100644
index 0000000..3f71518
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ClassificationsRequest implements Parcelable {
+    @NonNull
+    private final List<ContentSelection> mSelections;
+    @Nullable
+    private final Bundle mExtras;
+
+    private ClassificationsRequest(@NonNull List<ContentSelection> selections,
+            @Nullable Bundle extras) {
+        mSelections = selections;
+        mExtras = extras;
+    }
+
+    /**
+     * Return request selections.
+     */
+    public List<ContentSelection> getSelections() {
+        return mSelections;
+    }
+
+    /**
+     * Return the request extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(mSelections);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ClassificationsRequest> CREATOR =
+            new Creator<ClassificationsRequest>() {
+        @Override
+        public ClassificationsRequest createFromParcel(Parcel source) {
+            return new ClassificationsRequest(
+                    source.createTypedArrayList(ContentSelection.CREATOR),
+                    source.readBundle());
+        }
+
+        @Override
+        public ClassificationsRequest[] newArray(int size) {
+            return new ClassificationsRequest[size];
+        }
+    };
+
+    /**
+     * A builder for classifications request events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final List<ContentSelection> mSelections;
+        private Bundle mExtras;
+
+        public Builder(@NonNull List<ContentSelection> selections) {
+            mSelections = selections;
+        }
+
+        /**
+         * Sets the request extras.
+         */
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds a new request instance.
+         */
+        public ClassificationsRequest build() {
+            return new ClassificationsRequest(mSelections, mExtras);
+        }
+    }
+}
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.aidl b/core/java/android/app/contentsuggestions/ContentClassification.aidl
new file mode 100644
index 0000000..f67b2c8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.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.app.contentsuggestions;
+
+parcelable ContentClassification;
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.java b/core/java/android/app/contentsuggestions/ContentClassification.java
new file mode 100644
index 0000000..f18520f
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.java
@@ -0,0 +1,79 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentClassification implements Parcelable {
+    @NonNull
+    private final String mClassificationId;
+    @NonNull
+    private final Bundle mExtras;
+
+    public ContentClassification(@NonNull String classificationId, @NonNull Bundle extras) {
+        mClassificationId = classificationId;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the classification id.
+     */
+    public String getId() {
+        return mClassificationId;
+    }
+
+    /**
+     * Return the classification extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mClassificationId);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ContentClassification> CREATOR =
+            new Creator<ContentClassification>() {
+        @Override
+        public ContentClassification createFromParcel(Parcel source) {
+            return new ContentClassification(
+                    source.readString(),
+                    source.readBundle());
+        }
+
+        @Override
+        public ContentClassification[] newArray(int size) {
+            return new ContentClassification[size];
+        }
+    };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.aidl b/core/java/android/app/contentsuggestions/ContentSelection.aidl
new file mode 100644
index 0000000..e626d69
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.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.app.contentsuggestions;
+
+parcelable ContentSelection;
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.java b/core/java/android/app/contentsuggestions/ContentSelection.java
new file mode 100644
index 0000000..a8917f7
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.java
@@ -0,0 +1,79 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentSelection implements Parcelable {
+    @NonNull
+    private final String mSelectionId;
+    @NonNull
+    private final Bundle mExtras;
+
+    public ContentSelection(@NonNull String selectionId, @NonNull Bundle extras) {
+        mSelectionId = selectionId;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the selection id.
+     */
+    public String getId() {
+        return mSelectionId;
+    }
+
+    /**
+     * Return the selection extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mSelectionId);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ContentSelection> CREATOR =
+            new Creator<ContentSelection>() {
+        @Override
+        public ContentSelection createFromParcel(Parcel source) {
+            return new ContentSelection(
+                    source.readString(),
+                    source.readBundle());
+        }
+
+        @Override
+        public ContentSelection[] newArray(int size) {
+            return new ContentSelection[size];
+        }
+    };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
new file mode 100644
index 0000000..b4d8977
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -0,0 +1,230 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * When provided with content from an app, can suggest selections and classifications of that
+ * content.
+ *
+ * <p>The content is mainly a snapshot of a running task, the selections will be text and image
+ * selections with that image content. These mSelections can then be classified to find actions and
+ * entities on those selections.
+ *
+ * <p>Only accessible to blessed components such as Overview.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContentSuggestionsManager {
+    private static final String TAG = ContentSuggestionsManager.class.getSimpleName();
+
+    @Nullable
+    private final IContentSuggestionsManager mService;
+
+    /** @hide */
+    public ContentSuggestionsManager(@Nullable IContentSuggestionsManager service) {
+        mService = service;
+    }
+
+    /**
+     * Hints to the system that a new context image for the provided task should be sent to the
+     * system content suggestions service.
+     *
+     * @param taskId of the task to snapshot.
+     * @param imageContextRequestExtras sent with with request to provide implementation specific
+     *                                  extra information.
+     */
+    public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+        if (mService == null) {
+            Log.e(TAG, "provideContextImage called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.provideContextImage(taskId, imageContextRequestExtras);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Suggest content selections, based on the provided task id and optional
+     * location on screen provided in the request. Called after provideContextImage().
+     * The result can be passed to
+     * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+     *  to classify actions and entities on these selections.
+     *
+     * @param request containing the task and point location.
+     * @param callbackExecutor to execute the provided callback on.
+     * @param callback to receive the selections.
+     */
+    public void suggestContentSelections(
+            @NonNull SelectionsRequest request,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull SelectionsCallback callback) {
+        if (mService == null) {
+            Log.e(TAG,
+                    "suggestContentSelections called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.suggestContentSelections(
+                    request, new SelectionsCallbackWrapper(callback, callbackExecutor));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Classify actions and entities in content selections, as returned from
+     * suggestContentSelections. Note these selections may be modified by the
+     * caller before being passed here.
+     *
+     * @param request containing the selections to classify.
+     * @param callbackExecutor to execute the provided callback on.
+     * @param callback to receive the classifications.
+     */
+    public void classifyContentSelections(
+            @NonNull ClassificationsRequest request,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull ClassificationsCallback callback) {
+        if (mService == null) {
+            Log.e(TAG, "classifyContentSelections called, "
+                    + "but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.classifyContentSelections(
+                    request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Report telemetry for interaction with suggestions / classifications.
+     *
+     * @param requestId the id for the associated interaction
+     * @param interaction to report back to the system content suggestions service.
+     */
+    public void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction) {
+        if (mService == null) {
+            Log.e(TAG, "notifyInteraction called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.notifyInteraction(requestId, interaction);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback to receive content selections from
+     *  {@link #suggestContentSelections(SelectionsRequest, Executor, SelectionsCallback)}.
+     */
+    public interface SelectionsCallback {
+        /**
+         * Async callback called when the content suggestions service has selections available.
+         * These can be modified and sent back to the manager for classification. The contents of
+         * the selection is implementation dependent.
+         *
+         * @param statusCode as defined by the implementation of content suggestions service.
+         * @param selections not {@code null}, but can be size {@code 0}.
+         */
+        void onContentSelectionsAvailable(
+                int statusCode, @NonNull List<ContentSelection> selections);
+    }
+
+    /**
+     * Callback to receive classifications from
+     * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+     */
+    public interface ClassificationsCallback {
+        /**
+         * Async callback called when the content suggestions service has classified selections. The
+         * contents of the classification is implementation dependent.
+         *
+         * @param statusCode as defined by the implementation of content suggestions service.
+         * @param classifications not {@code null}, but can be size {@code 0}.
+         */
+        void onContentClassificationsAvailable(int statusCode,
+                @NonNull List<ContentClassification> classifications);
+    }
+
+    private static class SelectionsCallbackWrapper extends ISelectionsCallback.Stub {
+        private final SelectionsCallback mCallback;
+        private final Executor mExecutor;
+
+        SelectionsCallbackWrapper(
+                @NonNull SelectionsCallback callback, @NonNull Executor executor) {
+            mCallback = callback;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onContentSelectionsAvailable(
+                int statusCode, List<ContentSelection> selections) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mCallback.onContentSelectionsAvailable(statusCode, selections));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    private static final class ClassificationsCallbackWrapper extends
+            IClassificationsCallback.Stub {
+        private final ClassificationsCallback mCallback;
+        private final Executor mExecutor;
+
+        ClassificationsCallbackWrapper(@NonNull ClassificationsCallback callback,
+                @NonNull Executor executor) {
+            mCallback = callback;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onContentClassificationsAvailable(
+                int statusCode, List<ContentClassification> classifications) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mCallback.onContentClassificationsAvailable(statusCode, classifications));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
new file mode 100644
index 0000000..69f5d55
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.app.contentsuggestions;
+
+import android.app.contentsuggestions.ContentClassification;
+
+/** @hide */
+oneway interface IClassificationsCallback {
+    void onContentClassificationsAvailable(
+            int statusCode, in List<ContentClassification> classifications);
+}
diff --git a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
new file mode 100644
index 0000000..24f5ad8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IContentSuggestionsManager {
+    void provideContextImage(
+            int taskId,
+            in Bundle imageContextRequestExtras);
+    void suggestContentSelections(
+            in SelectionsRequest request,
+            in ISelectionsCallback callback);
+    void classifyContentSelections(
+            in ClassificationsRequest request,
+            in IClassificationsCallback callback);
+    void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
new file mode 100644
index 0000000..1952583
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.app.contentsuggestions;
+
+import android.app.contentsuggestions.ContentSelection;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface ISelectionsCallback {
+    void onContentSelectionsAvailable(int statusCode, in List<ContentSelection> selections);
+}
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.aidl b/core/java/android/app/contentsuggestions/SelectionsRequest.aidl
new file mode 100644
index 0000000..f5ce7c3
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.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.app.contentsuggestions;
+
+parcelable SelectionsRequest;
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.java b/core/java/android/app/contentsuggestions/SelectionsRequest.java
new file mode 100644
index 0000000..16f3e6b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.app.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class SelectionsRequest implements Parcelable {
+    private final int mTaskId;
+    @Nullable
+    private final Point mInterestPoint;
+    @Nullable
+    private final Bundle mExtras;
+
+    private SelectionsRequest(int taskId, @Nullable Point interestPoint, @Nullable Bundle extras) {
+        mTaskId = taskId;
+        mInterestPoint = interestPoint;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the request task id.
+     */
+    public int getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * Return the request point of interest.
+     */
+    public Point getInterestPoint() {
+        return mInterestPoint;
+    }
+
+    /**
+     * Return the request extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mTaskId);
+        dest.writeTypedObject(mInterestPoint, flags);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<SelectionsRequest> CREATOR =
+            new Creator<SelectionsRequest>() {
+        @Override
+        public SelectionsRequest createFromParcel(Parcel source) {
+            return new SelectionsRequest(
+                    source.readInt(), source.readTypedObject(Point.CREATOR), source.readBundle());
+        }
+
+        @Override
+        public SelectionsRequest[] newArray(int size) {
+            return new SelectionsRequest[size];
+        }
+    };
+
+    /**
+     * A builder for selections requests events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final int mTaskId;
+        private Point mInterestPoint;
+        private Bundle mExtras;
+
+        public Builder(int taskId) {
+            mTaskId = taskId;
+        }
+
+        /**
+         * Sets the request extras.
+         */
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Sets the request interest point.
+         */
+        public Builder setInterestPoint(@NonNull Point interestPoint) {
+            mInterestPoint = interestPoint;
+            return this;
+        }
+
+        /**
+         * Builds a new request instance.
+         */
+        public SelectionsRequest build() {
+            return new SelectionsRequest(mTaskId, mInterestPoint, mExtras);
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppPredictionContext.aidl b/core/java/android/app/prediction/AppPredictionContext.aidl
new file mode 100644
index 0000000..5767bf4
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionContext.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.app.prediction;
+
+parcelable AppPredictionContext;
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
new file mode 100644
index 0000000..87ccb66
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -0,0 +1,158 @@
+/*
+ * 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.app.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO(b/111701043): Add java docs
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionContext implements Parcelable {
+
+    private final int mPredictedTargetCount;
+    @NonNull
+    private final String mUiSurface;
+    @NonNull
+    private final String mPackageName;
+    @Nullable
+    private final Bundle mExtras;
+
+    private AppPredictionContext(@NonNull String uiSurface, int numPredictedTargets,
+            @NonNull String packageName, @Nullable Bundle extras) {
+        mUiSurface = uiSurface;
+        mPredictedTargetCount = numPredictedTargets;
+        mPackageName = packageName;
+        mExtras = extras;
+    }
+
+    private AppPredictionContext(Parcel parcel) {
+        mUiSurface = parcel.readString();
+        mPredictedTargetCount = parcel.readInt();
+        mPackageName = parcel.readString();
+        mExtras = parcel.readBundle();
+    }
+
+    public String getUiSurface() {
+        return mUiSurface;
+    }
+
+    public int getPredictedTargetCount() {
+        return mPredictedTargetCount;
+    }
+
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    @Nullable
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mUiSurface);
+        dest.writeInt(mPredictedTargetCount);
+        dest.writeString(mPackageName);
+        dest.writeBundle(mExtras);
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final Parcelable.Creator<AppPredictionContext> CREATOR =
+            new Parcelable.Creator<AppPredictionContext>() {
+                public AppPredictionContext createFromParcel(Parcel parcel) {
+                    return new AppPredictionContext(parcel);
+                }
+
+                public AppPredictionContext[] newArray(int size) {
+                    return new AppPredictionContext[size];
+                }
+            };
+
+    /**
+     * A builder for app prediction contexts.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        @NonNull
+        private final String mPackageName;
+
+        private int mPredictedTargetCount;
+        @Nullable
+        private String mUiSurface;
+        @Nullable
+        private Bundle mExtras;
+
+        /**
+         * @hide
+         */
+        public Builder(@NonNull Context context) {
+            mPackageName = context.getPackageName();
+        }
+
+
+        /**
+         * Sets the number of prediction targets as a hint.
+         */
+        public Builder setPredictedTargetCount(int predictedTargetCount) {
+            mPredictedTargetCount = predictedTargetCount;
+            return this;
+        }
+
+        /**
+         * Sets the UI surface.
+         */
+        public Builder setUiSurface(@Nullable String uiSurface) {
+            mUiSurface = uiSurface;
+            return this;
+        }
+
+        /**
+         * Sets the extras.
+         */
+        public Builder setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds a new context instance.
+         */
+        public AppPredictionContext build() {
+            return new AppPredictionContext(mUiSurface, mPredictedTargetCount, mPackageName,
+                    mExtras);
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
new file mode 100644
index 0000000..f8578d4
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -0,0 +1,47 @@
+/*
+ * 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.app.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.Context;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionManager {
+
+    private final Context mContext;
+
+    /**
+     * @hide
+     */
+    public AppPredictionManager(Context context) {
+        mContext = Preconditions.checkNotNull(context);
+    }
+
+    /**
+     * Creates a new app prediction session.
+     */
+    public AppPredictor createAppPredictionSession(
+            @NonNull AppPredictionContext predictionContext) {
+        return new AppPredictor(mContext, predictionContext);
+    }
+}
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.aidl b/core/java/android/app/prediction/AppPredictionSessionId.aidl
new file mode 100644
index 0000000..e829526
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionSessionId.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.app.prediction;
+
+parcelable AppPredictionSessionId;
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
new file mode 100644
index 0000000..1d7308e
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionSessionId.java
@@ -0,0 +1,86 @@
+/*
+ * 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.app.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionSessionId implements Parcelable {
+
+    private final String mId;
+
+    /**
+     * @hide
+     */
+    public AppPredictionSessionId(@NonNull String id) {
+        mId = id;
+    }
+
+    private AppPredictionSessionId(Parcel p) {
+        mId = p.readString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!getClass().equals(o != null ? o.getClass() : null)) return false;
+
+        AppPredictionSessionId other = (AppPredictionSessionId) o;
+        return mId.equals(other.mId);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return mId;
+    }
+
+    @Override
+    public int hashCode() {
+        // Ensure that the id has a consistent hash
+        return mId.hashCode();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final Parcelable.Creator<AppPredictionSessionId> CREATOR =
+            new Parcelable.Creator<AppPredictionSessionId>() {
+                public AppPredictionSessionId createFromParcel(Parcel parcel) {
+                    return new AppPredictionSessionId(parcel);
+                }
+
+                public AppPredictionSessionId[] newArray(int size) {
+                    return new AppPredictionSessionId[size];
+                }
+            };
+}
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
new file mode 100644
index 0000000..2ddbd08c
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -0,0 +1,257 @@
+/*
+ * 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.app.prediction;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.prediction.IPredictionCallback.Stub;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ *
+ * <p>
+ * Usage: <pre> {@code
+ *
+ * class MyActivity {
+ *    private AppPredictor mClient
+ *
+ *    void onCreate() {
+ *         mClient = new AppPredictor(...)
+ *    }
+ *
+ *    void onStart() {
+ *        mClient.requestPredictionUpdate();
+ *    }
+ *
+ *    void onDestroy() {
+ *        mClient.close();
+ *    }
+ *
+ * }</pre>
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictor {
+
+    private static final String TAG = AppPredictor.class.getSimpleName();
+
+
+    private final IPredictionManager mPredictionManager;
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private final AtomicBoolean mIsClosed = new AtomicBoolean(false);
+
+    private final AppPredictionSessionId mSessionId;
+    private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
+
+    /**
+     * Creates a new Prediction client.
+     * <p>
+     * The caller should call {@link AppPredictor#destroy()} to dispose the client once it
+     * no longer used.
+     *
+     * @param predictionContext The prediction context
+     */
+    AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) {
+        IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
+        mPredictionManager = IPredictionManager.Stub.asInterface(b);
+        mSessionId = new AppPredictionSessionId(
+                context.getPackageName() + ":" + UUID.randomUUID().toString());
+        try {
+            mPredictionManager.createPredictionSession(predictionContext, mSessionId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to create predictor", e);
+            return;
+        }
+
+        mCloseGuard.open("close");
+    }
+
+    /**
+     * Notifies the prediction service of an app target event.
+     */
+    public void notifyAppTargetEvent(@NonNull AppTargetEvent event) {
+        try {
+            mPredictionManager.notifyAppTargetEvent(mSessionId, event);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to notify app target event", e);
+        }
+    }
+
+    /**
+     * Notifies the prediction service when the targets in a launch location are shown to the user.
+     */
+    public void notifyLocationShown(@NonNull String launchLocation,
+            @NonNull List<AppTargetId> targetIds) {
+        try {
+            mPredictionManager.notifyLocationShown(mSessionId, launchLocation,
+                    new ParceledListSlice<>(targetIds));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to notify location shown event", e);
+        }
+    }
+
+    /**
+     * Requests the prediction service provide continuous updates of App predictions via the
+     * provided callback, until the given callback is unregistered.
+     *
+     * @see Callback#onTargetsAvailable(List)
+     */
+    public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull AppPredictor.Callback callback) {
+        if (mRegisteredCallbacks.containsKey(callback)) {
+            // Skip if this callback is already registered
+            return;
+        }
+        try {
+            final CallbackWrapper callbackWrapper = new CallbackWrapper(callbackExecutor,
+                    callback::onTargetsAvailable);
+            mPredictionManager.registerPredictionUpdates(mSessionId, callbackWrapper);
+            mRegisteredCallbacks.put(callback, callbackWrapper);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register for prediction updates", e);
+        }
+    }
+
+    /**
+     * Requests the prediction service to stop providing continuous updates to the provided
+     * callback until the callback is re-registered.
+     */
+    public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) {
+        if (!mRegisteredCallbacks.containsKey(callback)) {
+            // Skip if this callback was never registered
+            return;
+        }
+        try {
+            final CallbackWrapper callbackWrapper = mRegisteredCallbacks.remove(callback);
+            mPredictionManager.unregisterPredictionUpdates(mSessionId, callbackWrapper);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to unregister for prediction updates", e);
+        }
+    }
+
+    /**
+     * Requests the prediction service to dispatch a new set of App predictions via the provided
+     * callback.
+     *
+     * @see Callback#onTargetsAvailable(List)
+     */
+    public void requestPredictionUpdate() {
+        try {
+            mPredictionManager.requestPredictionUpdate(mSessionId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to request prediction update", e);
+        }
+    }
+
+    /**
+     * Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the
+     * ranker is not available.
+     */
+    @Nullable
+    public void sortTargets(@NonNull List<AppTarget> targets,
+            @NonNull Executor callbackExecutor, @NonNull Consumer<List<AppTarget>> callback) {
+        try {
+            mPredictionManager.sortAppTargets(mSessionId, new ParceledListSlice(targets),
+                    new CallbackWrapper(callbackExecutor, callback));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to sort targets", e);
+        }
+    }
+
+    /**
+     * Destroys the client and unregisters the callback. Any method on this class after this call
+     * with throw {@link IllegalStateException}.
+     *
+     * TODO(b/111701043): Add state check in other methods.
+     */
+    public void destroy() {
+        if (!mIsClosed.getAndSet(true)) {
+            mCloseGuard.close();
+
+            // Do destroy;
+            try {
+                mPredictionManager.onDestroyPredictionSession(mSessionId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify app target event", e);
+            }
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+            destroy();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Callback for receiving prediction updates.
+     */
+    public interface Callback {
+
+        /**
+         * Called when a new set of predicted app targets are available.
+         * @param targets Sorted list of predicted targets
+         */
+        void onTargetsAvailable(@NonNull List<AppTarget> targets);
+    }
+
+    static class CallbackWrapper extends Stub {
+
+        private final Consumer<List<AppTarget>> mCallback;
+        private final Executor mExecutor;
+
+        CallbackWrapper(@NonNull Executor callbackExecutor,
+                @NonNull Consumer<List<AppTarget>> callback) {
+            mCallback = callback;
+            mExecutor = callbackExecutor;
+        }
+
+        @Override
+        public void onResult(ParceledListSlice result) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.accept(result.getList()));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppTarget.aidl b/core/java/android/app/prediction/AppTarget.aidl
new file mode 100644
index 0000000..e4e2bc2
--- /dev/null
+++ b/core/java/android/app/prediction/AppTarget.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.app.prediction;
+
+parcelable AppTarget;
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
new file mode 100644
index 0000000..99c1c44
--- /dev/null
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -0,0 +1,166 @@
+/*
+ * 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.app.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.pm.ShortcutInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A representation of a launchable target.
+ * @hide
+ */
+@SystemApi
+public final class AppTarget implements Parcelable {
+
+    private final AppTargetId mId;
+    private final String mPackageName;
+    private final String mClassName;
+    private final UserHandle mUser;
+
+    private final ShortcutInfo mShortcutInfo;
+
+    private int mRank;
+
+    /**
+     * @hide
+     */
+    public AppTarget(@NonNull AppTargetId id, @NonNull String packageName,
+            @Nullable String className, @NonNull UserHandle user) {
+        mId = id;
+        mShortcutInfo = null;
+
+        mPackageName = Preconditions.checkNotNull(packageName);
+        mClassName = className;
+        mUser = Preconditions.checkNotNull(user);
+    }
+
+    /**
+     * @hide
+     */
+    public AppTarget(@NonNull AppTargetId id, @NonNull ShortcutInfo shortcutInfo) {
+        mId = id;
+        mShortcutInfo = Preconditions.checkNotNull(shortcutInfo);
+
+        mPackageName = mShortcutInfo.getPackage();
+        mUser = mShortcutInfo.getUserHandle();
+        mClassName = null;
+    }
+
+    private AppTarget(Parcel parcel) {
+        mId = parcel.readTypedObject(AppTargetId.CREATOR);
+        mShortcutInfo = parcel.readTypedObject(ShortcutInfo.CREATOR);
+        if (mShortcutInfo == null) {
+            mPackageName = parcel.readString();
+            mClassName = parcel.readString();
+            mUser = UserHandle.of(parcel.readInt());
+        } else {
+            mPackageName = mShortcutInfo.getPackage();
+            mUser = mShortcutInfo.getUserHandle();
+            mClassName = null;
+        }
+        mRank = parcel.readInt();
+    }
+
+    /**
+     * Returns the target id.
+     */
+    @NonNull
+    public AppTargetId getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the class name for the app target.
+     */
+    @Nullable
+    public String getClassName() {
+        return mClassName;
+    }
+
+    /**
+     * Returns the package name for the app target.
+     */
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Returns the user for the app target.
+     */
+    @NonNull
+    public UserHandle getUser() {
+        return mUser;
+    }
+
+    /**
+     * Returns the shortcut info for the target.
+     */
+    @Nullable
+    public ShortcutInfo getShortcutInfo() {
+        return mShortcutInfo;
+    }
+
+    /**
+     * Sets the rank of the for the target.
+     * @hide
+     */
+    public void setRank(int rank) {
+        mRank = rank;
+    }
+
+    public int getRank() {
+        return mRank;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedObject(mId, flags);
+        dest.writeTypedObject(mShortcutInfo, flags);
+        if (mShortcutInfo == null) {
+            dest.writeString(mPackageName);
+            dest.writeString(mClassName);
+            dest.writeInt(mUser.getIdentifier());
+        }
+        dest.writeInt(mRank);
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final Parcelable.Creator<AppTarget> CREATOR =
+            new Parcelable.Creator<AppTarget>() {
+                public AppTarget createFromParcel(Parcel parcel) {
+                    return new AppTarget(parcel);
+                }
+
+                public AppTarget[] newArray(int size) {
+                    return new AppTarget[size];
+                }
+            };
+}
diff --git a/core/java/android/app/prediction/AppTargetEvent.aidl b/core/java/android/app/prediction/AppTargetEvent.aidl
new file mode 100644
index 0000000..ebed2da
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetEvent.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.app.prediction;
+
+parcelable AppTargetEvent;
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
new file mode 100644
index 0000000..18317e1
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -0,0 +1,154 @@
+/*
+ * 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.app.prediction;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A representation of an app target event.
+ * @hide
+ */
+@SystemApi
+public final class AppTargetEvent implements Parcelable {
+
+    /**
+     * @hide
+     */
+    @IntDef({ACTION_LAUNCH, ACTION_DISMISS, ACTION_PIN})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ActionType {}
+
+    /**
+     * Event type constant indicating an app target has been launched.
+     */
+    public static final int ACTION_LAUNCH = 1;
+
+    /**
+     * Event type constant indicating an app target has been dismissed.
+     */
+    public static final int ACTION_DISMISS = 2;
+
+    /**
+     * Event type constant indicating an app target has been pinned.
+     */
+    public static final int ACTION_PIN = 3;
+
+    private final AppTarget mTarget;
+    private final String mLocation;
+    private final int mAction;
+
+    private AppTargetEvent(@Nullable AppTarget target, @Nullable String location,
+            @ActionType int actionType) {
+        mTarget = target;
+        mLocation = location;
+        mAction = actionType;
+    }
+
+    private AppTargetEvent(Parcel parcel) {
+        mTarget = parcel.readParcelable(null);
+        mLocation = parcel.readString();
+        mAction = parcel.readInt();
+    }
+
+    /**
+     * Returns the app target.
+     */
+    @Nullable
+    public AppTarget getTarget() {
+        return mTarget;
+    }
+
+    /**
+     * Returns the launch location.
+     */
+    @NonNull
+    public String getLaunchLocation() {
+        return mLocation;
+    }
+
+    /**
+     * Returns the action type.
+     */
+    @NonNull
+    public int getAction() {
+        return mAction;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mTarget, 0);
+        dest.writeString(mLocation);
+        dest.writeInt(mAction);
+    }
+
+    /**
+     * @see Creator
+     */
+    public static final Creator<AppTargetEvent> CREATOR =
+            new Creator<AppTargetEvent>() {
+                public AppTargetEvent createFromParcel(Parcel parcel) {
+                    return new AppTargetEvent(parcel);
+                }
+
+                public AppTargetEvent[] newArray(int size) {
+                    return new AppTargetEvent[size];
+                }
+            };
+
+    /**
+     * A builder for app target events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private AppTarget mTarget;
+        private String mLocation;
+        private @ActionType int mAction;
+
+        public Builder(@Nullable AppTarget target, @ActionType int actionType) {
+            mTarget = target;
+            mAction = actionType;
+        }
+
+        /**
+         * Sets the launch location.
+         */
+        public Builder setLaunchLocation(String location) {
+            mLocation = location;
+            return this;
+        }
+
+        /**
+         * Builds a new event instance.
+         */
+        public AppTargetEvent build() {
+            return new AppTargetEvent(mTarget, mLocation, mAction);
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppTargetId.aidl b/core/java/android/app/prediction/AppTargetId.aidl
new file mode 100644
index 0000000..bf69eea
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetId.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.app.prediction;
+
+parcelable AppTargetId;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
new file mode 100644
index 0000000..0b8fb47
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetId.java
@@ -0,0 +1,90 @@
+/*
+ * 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.app.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The id for a prediction target.
+ * @hide
+ */
+@SystemApi
+public final class AppTargetId implements Parcelable {
+
+    @NonNull
+    private final String mId;
+
+    /**
+     * @hide
+     */
+    public AppTargetId(@NonNull String id) {
+        mId = id;
+    }
+
+    private AppTargetId(Parcel parcel) {
+        mId = parcel.readString();
+    }
+
+    /**
+     * Returns the id.
+     * @hide
+     */
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!getClass().equals(o != null ? o.getClass() : null)) return false;
+
+        AppTargetId other = (AppTargetId) o;
+        return mId.equals(other.mId);
+    }
+
+    @Override
+    public int hashCode() {
+        // Ensure that the id has a consistent hash
+        return mId.hashCode();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+    }
+
+    /**
+     * @see Creator
+     */
+    public static final Creator<AppTargetId> CREATOR =
+            new Creator<AppTargetId>() {
+                public AppTargetId createFromParcel(Parcel parcel) {
+                    return new AppTargetId(parcel);
+                }
+
+                public AppTargetId[] newArray(int size) {
+                    return new AppTargetId[size];
+                }
+            };
+}
diff --git a/core/java/android/app/prediction/IPredictionCallback.aidl b/core/java/android/app/prediction/IPredictionCallback.aidl
new file mode 100644
index 0000000..f6f241e
--- /dev/null
+++ b/core/java/android/app/prediction/IPredictionCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.prediction;
+
+import android.content.pm.ParceledListSlice;
+
+/**
+ * @hide
+ */
+oneway interface IPredictionCallback {
+
+    void onResult(in ParceledListSlice result);
+}
diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl
new file mode 100644
index 0000000..114a1ff
--- /dev/null
+++ b/core/java/android/app/prediction/IPredictionManager.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.app.prediction;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.IPredictionCallback;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * @hide
+ */
+interface IPredictionManager {
+
+    void createPredictionSession(in AppPredictionContext context,
+            in AppPredictionSessionId sessionId);
+
+    void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
+
+    void notifyLocationShown(in AppPredictionSessionId sessionId, in String launchLocation,
+            in ParceledListSlice targetIds);
+
+    void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
+            in IPredictionCallback callback);
+
+    void registerPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void unregisterPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void requestPredictionUpdate(in AppPredictionSessionId sessionId);
+
+    void onDestroyPredictionSession(in AppPredictionSessionId sessionId);
+}
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 0c9b41bf..2964fbc 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -50,4 +50,6 @@
     boolean removeRoleHolderFromController(in String roleName, in String packageName);
 
     List<String> getHeldRolesFromController(in String packageName);
+
+    String getDefaultSmsPackage(int userId);
 }
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 2d630a6..27581fc 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -68,6 +69,8 @@
 
     /**
      * The name of the dialer role.
+     *
+     * @see Intent#ACTION_DIAL
      */
     public static final String ROLE_DIALER = "android.app.role.DIALER";
 
@@ -100,6 +103,75 @@
     public static final String ROLE_MUSIC = "android.app.role.MUSIC";
 
     /**
+     * The name of the home role.
+     *
+     * @see Intent#CATEGORY_HOME
+     */
+    public static final String ROLE_HOME = "android.app.role.HOME";
+
+    /**
+     * The name of the emergency role
+     *
+     * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
+     */
+    public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
+
+    /**
+     * The name of the car mode dialer app role.
+     * <p>
+     * Similar to the {@link #ROLE_DIALER dialer} role, this role determines which app is
+     * responsible for showing the user interface for ongoing calls on the device. It is only used
+     * when the device is in car mode.
+     *
+     * @see #ROLE_DIALER
+     * @see android.app.UiModeManager#ACTION_ENTER_CAR_MODE
+     * @see android.telecom.InCallService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+
+    /**
+     * The name of the proxy calling role.
+     * <p>
+     * A proxy calling app provides a means to re-write the phone number for an outgoing call to
+     * place the call through a proxy calling service.
+     *
+     * @see android.telecom.CallRedirectionService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_PROXY_CALLING_APP = "android.app.role.PROXY_CALLING_APP";
+
+    /**
+     * The name of the call screening and caller id role.
+     *
+     * @see android.telecom.CallScreeningService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_CALL_SCREENING_APP = "android.app.role.CALL_SCREENING_APP";
+
+    /**
+     * The name of the call companion app role.
+     * <p>
+     * A call companion app provides no user interface for calls, but will be bound to by Telecom
+     * when there are active calls on the device. Companion apps for wearable devices are an
+     * acceptable use-case.
+     * <p>
+     * Multiple apps may hold this role at the same time.
+     *
+     * @see android.telecom.InCallService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
+
+    /**
      * The action used to request user approval of a role for an application.
      *
      * @hide
@@ -542,7 +614,6 @@
         }
     }
 
-
     /**
      * Returns the list of all roles that the given package is currently holding
      *
@@ -563,6 +634,22 @@
         }
     }
 
+    /**
+     * Allows getting the role holder for {@link #ROLE_SMS} without
+     * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
+     * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
+     *
+     * @hide
+     */
+    @Nullable
+    public String getDefaultSmsPackage(@UserIdInt int userId) {
+        try {
+            return mService.getDefaultSmsPackage(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {
 
         @NonNull
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index a2b7d58..8ee9e53 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -36,6 +36,11 @@
     private Configuration mConfiguration;
 
     @Override
+    public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+        client.updatePendingActivityConfiguration(token, mConfiguration);
+    }
+
+    @Override
     public void execute(ClientTransactionHandler client, IBinder token,
             PendingTransactionActions pendingActions) {
         // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index eb7be6f..cefc700 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -337,6 +337,15 @@
     public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
 
     /**
+     * @hide Flag for {@link #bindService}: the service being bound to represents a
+     * protected system component, so must have association restrictions applied to it.
+     * That is, a system config must have one or more allow-association tags limiting
+     * which packages it can interact with.  If it does not have any such association
+     * restrictions, a default empty set will be created.
+     */
+    public static final int BIND_RESTRICT_ASSOCIATIONS = 0x00200000;
+
+    /**
      * @hide Flag for {@link #bindService}: allows binding to a service provided
      * by an instant app. Note that the caller may not have access to the instant
      * app providing the service which is a violation of the instant app sandbox.
@@ -3093,6 +3102,7 @@
             VIBRATOR_SERVICE,
             //@hide: STATUS_BAR_SERVICE,
             CONNECTIVITY_SERVICE,
+            //@hide: IP_MEMORY_STORE_SERVICE,
             IPSEC_SERVICE,
             //@hide: UPDATE_LOCK_SERVICE,
             //@hide: NETWORKMANAGEMENT_SERVICE,
@@ -3630,6 +3640,14 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.net.IpMemoryStore} to store and read information about
+     * known networks.
+     * @hide
+     */
+    public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
      * IPSec.
      *
@@ -3975,6 +3993,24 @@
     public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
 
     /**
+     * Used for getting content selections and classifications for task snapshots.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
+
+    /**
+     * Official published name of the app prediction service.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String APP_PREDICTION_SERVICE = "app_prediction";
+
+    /**
      * Use with {@link #getSystemService(String)} to access the
      * {@link com.android.server.voiceinteraction.SoundTriggerService}.
      *
@@ -4427,6 +4463,16 @@
     public static final String STATS_MANAGER = "stats";
 
     /**
+     * Service to capture a bugreport.
+     * @see #getSystemService(String)
+     * @see android.os.BugreportManager
+     * @hide
+     */
+    // TODO: Expose API when the implementation is more complete.
+    // @SystemApi
+    public static final String BUGREPORT_SERVICE = "bugreport";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.content.om.OverlayManager} for managing overlay packages.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index de810e8..e37126b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1953,16 +1953,35 @@
     public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
 
     /**
+     * Intent extra: The name of a permission group.
+     * <p>
+     * Type: String
+     * </p>
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PERMISSION_GROUP_NAME =
+            "android.intent.extra.PERMISSION_GROUP_NAME";
+
+    /**
      * Activity action: Launch UI to review app uses of permissions.
      * <p>
      * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission name
-     * that will be displayed by the launched UI.
+     * that will be displayed by the launched UI.  Do not pass both this and
+     * {@link #EXTRA_PERMISSION_GROUP_NAME} .
+     * </p>
+     * <p>
+     * Input: {@link #EXTRA_PERMISSION_GROUP_NAME} specifies the permission group name
+     * that will be displayed by the launched UI.  Do not pass both this and
+     * {@link #EXTRA_PERMISSION_NAME}.
      * </p>
      * <p>
      * Output: Nothing.
      * </p>
      *
      * @see #EXTRA_PERMISSION_NAME
+     * @see #EXTRA_PERMISSION_GROUP_NAME
      *
      * @hide
      */
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0edb36c..3cfbe0c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -505,6 +505,22 @@
      */
     public int flags;
 
+    /**
+     * Bit in {@link #privateFlags} indicating if the activity should be shown when locked in case
+     * an activity behind this can also be shown when locked.
+     * See android.R.attr#inheritShowWhenLocked
+     * @hide
+     */
+    public static final int FLAG_INHERIT_SHOW_WHEN_LOCKED = 0x1;
+
+    /**
+     * Options that have been set in the activity declaration in the manifest.
+     * These include:
+     * {@link #FLAG_INHERIT_SHOW_WHEN_LOCKED}.
+     * @hide
+     */
+    public int privateFlags;
+
     /** @hide */
     @IntDef(prefix = { "SCREEN_ORIENTATION_" }, value = {
             SCREEN_ORIENTATION_UNSET,
@@ -975,6 +991,7 @@
         taskAffinity = orig.taskAffinity;
         targetActivity = orig.targetActivity;
         flags = orig.flags;
+        privateFlags = orig.privateFlags;
         screenOrientation = orig.screenOrientation;
         configChanges = orig.configChanges;
         softInputMode = orig.softInputMode;
@@ -1122,9 +1139,10 @@
                     + " targetActivity=" + targetActivity
                     + " persistableMode=" + persistableModeToString());
         }
-        if (launchMode != 0 || flags != 0 || theme != 0) {
+        if (launchMode != 0 || flags != 0 || privateFlags != 0 || theme != 0) {
             pw.println(prefix + "launchMode=" + launchMode
                     + " flags=0x" + Integer.toHexString(flags)
+                    + " privateFlags=0x" + Integer.toHexString(privateFlags)
                     + " theme=0x" + Integer.toHexString(theme));
         }
         if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED
@@ -1178,6 +1196,7 @@
         dest.writeString(targetActivity);
         dest.writeString(launchToken);
         dest.writeInt(flags);
+        dest.writeInt(privateFlags);
         dest.writeInt(screenOrientation);
         dest.writeInt(configChanges);
         dest.writeInt(softInputMode);
@@ -1307,6 +1326,7 @@
         targetActivity = source.readString();
         launchToken = source.readString();
         flags = source.readInt();
+        privateFlags = source.readInt();
         screenOrientation = source.readInt();
         configChanges = source.readInt();
         softInputMode = source.readInt();
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2978058..576466f 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1866,7 +1866,15 @@
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
     }
 
-    /** @hide */
+    /**
+     * Check whether the application is encryption aware.
+     *
+     * @see #isDirectBootAware()
+     * @see #isPartiallyDirectBootAware()
+     *
+     * @hide
+     */
+    @SystemApi
     public boolean isEncryptionAware() {
         return isDirectBootAware() || isPartiallyDirectBootAware();
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2b266b7..0fc50c6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1621,7 +1621,7 @@
             }
 
             final AttributeSet attrs = parser;
-            return parseApkLite(apkPath, parser, attrs, signingDetails);
+            return parseApkLite(apkPath, parser, attrs, signingDetails, flags);
 
         } catch (XmlPullParserException | IOException | RuntimeException e) {
             Slog.w(TAG, "Failed to parse " + apkPath, e);
@@ -1708,7 +1708,7 @@
     }
 
     private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
-            SigningDetails signingDetails)
+            SigningDetails signingDetails, int flags)
             throws IOException, XmlPullParserException, PackageParserException {
         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
 
@@ -1716,11 +1716,12 @@
         int versionCode = 0;
         int versionCodeMajor = 0;
         int revisionCode = 0;
+        int targetSdkVersion = 0;
         boolean coreApp = false;
         boolean debuggable = false;
         boolean multiArch = false;
         boolean use32bitAbi = false;
-        boolean extractNativeLibs = true;
+        Boolean extractNativeLibsProvided = null;
         boolean isolatedSplits = false;
         boolean isFeatureSplit = false;
         boolean isSplitRequired = false;
@@ -1785,7 +1786,8 @@
                         use32bitAbi = attrs.getAttributeBooleanValue(i, false);
                     }
                     if ("extractNativeLibs".equals(attr)) {
-                        extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
+                        extractNativeLibsProvided = Boolean.valueOf(
+                                attrs.getAttributeBooleanValue(i, true));
                     }
                     if ("preferCodeIntegrity".equals(attr)) {
                         preferCodeIntegrity = attrs.getAttributeBooleanValue(i, false);
@@ -1803,9 +1805,51 @@
                             PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                             "<uses-split> tag requires 'android:name' attribute");
                 }
+            } else if (TAG_USES_SDK.equals(parser.getName())) {
+                final String[] errorMsg = new String[1];
+                Pair<Integer, Integer> versions = deriveSdkVersions(new AbstractVersionsAccessor() {
+                    @Override public String getMinSdkVersionCode() {
+                        return getAttributeAsString("minSdkVersion");
+                    }
+
+                    @Override public int getMinSdkVersion() {
+                        return getAttributeAsInt("minSdkVersion");
+                    }
+
+                    @Override public String getTargetSdkVersionCode() {
+                        return getAttributeAsString("targetSdkVersion");
+                    }
+
+                    @Override public int getTargetSdkVersion() {
+                        return getAttributeAsInt("targetSdkVersion");
+                    }
+
+                    private String getAttributeAsString(String name) {
+                        return attrs.getAttributeValue(ANDROID_RESOURCES, name);
+                    }
+
+                    private int getAttributeAsInt(String name) {
+                        try {
+                            return attrs.getAttributeIntValue(ANDROID_RESOURCES, name, -1);
+                        } catch (NumberFormatException e) {
+                            return -1;
+                        }
+                    }
+                }, flags, errorMsg);
+
+                if (versions == null) {
+                    throw new PackageParserException(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, errorMsg[0]);
+                }
+
+                targetSdkVersion = versions.second;
             }
         }
 
+        final boolean extractNativeLibsDefault = targetSdkVersion < Build.VERSION_CODES.Q;
+        final boolean extractNativeLibs = (extractNativeLibsProvided != null)
+                ? extractNativeLibsProvided : extractNativeLibsDefault;
+
         if (preferCodeIntegrity && extractNativeLibs) {
             throw new PackageParserException(
                     PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
@@ -2215,65 +2259,60 @@
 
             } else if (tagName.equals(TAG_USES_SDK)) {
                 if (SDK_VERSION > 0) {
-                    sa = res.obtainAttributes(parser,
-                            com.android.internal.R.styleable.AndroidManifestUsesSdk);
+                    sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
+                    final TypedArray saFinal = sa;
+                    Pair<Integer, Integer> versions = deriveSdkVersions(
+                            new AbstractVersionsAccessor() {
+                                @Override public String getMinSdkVersionCode() {
+                                    return getAttributeAsString(
+                                            R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+                                }
 
-                    int minVers = 1;
-                    String minCode = null;
-                    int targetVers = 0;
-                    String targetCode = null;
+                                @Override public int getMinSdkVersion() {
+                                    return getAttributeAsInt(
+                                            R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+                                }
 
-                    TypedValue val = sa.peekValue(
-                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
-                    if (val != null) {
-                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                            minCode = val.string.toString();
-                        } else {
-                            // If it's not a string, it's an integer.
-                            minVers = val.data;
-                        }
+                                @Override public String getTargetSdkVersionCode() {
+                                    return getAttributeAsString(
+                                            R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+                                }
+
+                                @Override public int getTargetSdkVersion() {
+                                    return getAttributeAsInt(
+                                            R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+                                }
+
+                                private String getAttributeAsString(int index) {
+                                    TypedValue val = saFinal.peekValue(index);
+                                    if (val != null && val.type == TypedValue.TYPE_STRING
+                                            && val.string != null) {
+                                        return val.string.toString();
+                                    }
+                                    return null;
+                                }
+
+                                private int getAttributeAsInt(int index) {
+                                    TypedValue val = saFinal.peekValue(index);
+                                    if (val != null && val.type != TypedValue.TYPE_STRING) {
+                                        // If it's not a string, it's an integer.
+                                        return val.data;
+                                    }
+                                    return -1;
+                                }
+                            }, flags, outError);
+
+                    if (versions == null) {
+                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                        return null;
                     }
 
-                    val = sa.peekValue(
-                            com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
-                    if (val != null) {
-                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                            targetCode = val.string.toString();
-                            if (minCode == null) {
-                                minCode = targetCode;
-                            }
-                        } else {
-                            // If it's not a string, it's an integer.
-                            targetVers = val.data;
-                        }
-                    } else {
-                        targetVers = minVers;
-                        targetCode = minCode;
-                    }
+                    pkg.applicationInfo.minSdkVersion = versions.first;
+                    pkg.applicationInfo.targetSdkVersion = versions.second;
 
                     sa.recycle();
-
-                    final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
-                            SDK_VERSION, SDK_CODENAMES, outError);
-                    if (minSdkVersion < 0) {
-                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
-                        return null;
-                    }
-
-                    boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0;
-                    final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
-                            targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch);
-                    if (targetSdkVersion < 0) {
-                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
-                        return null;
-                    }
-
-                    pkg.applicationInfo.minSdkVersion = minSdkVersion;
-                    pkg.applicationInfo.targetSdkVersion = targetSdkVersion;
                 }
-
                 XmlUtils.skipCurrentTag(parser);
-
             } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
                 sa = res.obtainAttributes(parser,
                         com.android.internal.R.styleable.AndroidManifestSupportsScreens);
@@ -2675,6 +2714,67 @@
         return -1;
     }
 
+    private interface AbstractVersionsAccessor {
+        /** Returns minimum SDK version code string, or null if absent. */
+        String getMinSdkVersionCode();
+
+        /** Returns minimum SDK version code, or -1 if absent. */
+        int getMinSdkVersion();
+
+        /** Returns target SDK version code string, or null if absent. */
+        String getTargetSdkVersionCode();
+
+        /** Returns target SDK version code, or -1 if absent. */
+        int getTargetSdkVersion();
+    }
+
+    private static @Nullable Pair<Integer, Integer> deriveSdkVersions(
+            @NonNull AbstractVersionsAccessor accessor, int flags, String[] outError) {
+        int minVers = 1;
+        String minCode = null;
+        int targetVers = 0;
+        String targetCode = null;
+
+        String code = accessor.getMinSdkVersionCode();
+        int version = accessor.getMinSdkVersion();
+        // Check integer first since code is almost never a null string (e.g. "28").
+        if (version >= 0) {
+            minVers = version;
+        } else if (code != null) {
+            minCode = code;
+        }
+
+        code = accessor.getTargetSdkVersionCode();
+        version = accessor.getTargetSdkVersion();
+        // Check integer first since code is almost never a null string (e.g. "28").
+        if (version >= 0) {
+            targetVers = version;
+        } else if (code != null) {
+            targetCode = code;
+            if (minCode == null) {
+                minCode = targetCode;
+            }
+        } else {
+            targetVers = minVers;
+            targetCode = minCode;
+        }
+
+        final int minSdkVersion = computeMinSdkVersion(minVers, minCode,
+                SDK_VERSION, SDK_CODENAMES, outError);
+        if (minSdkVersion < 0) {
+            return null;
+        }
+
+        boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0;
+        final int targetSdkVersion = computeTargetSdkVersion(targetVers,
+                targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch);
+        if (targetSdkVersion < 0) {
+            return null;
+        }
+
+        return Pair.create(minSdkVersion, targetSdkVersion);
+    }
+
     /**
      * Computes the minSdkVersion to use at runtime. If the package is not
      * compatible with this platform, populates {@code outError[0]} with an
@@ -4546,6 +4646,9 @@
                 a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
             }
 
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked, false)) {
+                a.info.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
+            }
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
@@ -4925,6 +5028,7 @@
         info.targetActivity = targetActivity;
         info.configChanges = target.info.configChanges;
         info.flags = target.info.flags;
+        info.privateFlags = target.info.privateFlags;
         info.icon = target.info.icon;
         info.logo = target.info.logo;
         info.banner = target.info.banner;
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index be6ed51..74dd08f 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -29,8 +29,11 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.os.BaseBundle;
+import android.os.Debug;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -43,6 +46,9 @@
  * @hide
  */
 public class PackageUserState {
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "PackageUserState";
+
     public long ceDataInode;
     public boolean installed;
     public boolean stopped;
@@ -132,12 +138,12 @@
         final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
         final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
         if (!isAvailable(flags)
-                && !(isSystemApp && matchUninstalled)) return false;
-        if (!isEnabled(componentInfo, flags)) return false;
+                && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags);
+        if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags);
 
         if ((flags & MATCH_SYSTEM_ONLY) != 0) {
             if (!isSystemApp) {
-                return false;
+                return reportIfDebug(false, flags);
             }
         }
 
@@ -145,7 +151,16 @@
                 && !componentInfo.directBootAware;
         final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
                 && componentInfo.directBootAware;
-        return matchesUnaware || matchesAware;
+        return reportIfDebug(matchesUnaware || matchesAware, flags);
+    }
+
+    private boolean reportIfDebug(boolean result, int flags) {
+        if (DEBUG && !result) {
+            Slog.i(LOG_TAG, "No match!; flags: "
+                    + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
+                    + Debug.getCaller());
+        }
+        return result;
     }
 
     /**
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index a8c3b88..6e519c1 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -475,6 +475,14 @@
         final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
         for (ResolveInfo resolveInfo : resolveInfos) {
             try {
+                // if this package is not one of those changedUids, we don't need to scan it,
+                // since nothing in it changed, so save a call to parseServiceInfo, which
+                // can cause a large amount of the package apk to be loaded into memory.
+                // if this is the initial scan, changedUids will be null, and containsUid will
+                // trivially return true, and will call parseServiceInfo
+                if (!containsUid(changedUids, resolveInfo.serviceInfo.applicationInfo.uid)) {
+                    continue;
+                }
                 ServiceInfo<V> info = parseServiceInfo(resolveInfo);
                 if (info == null) {
                     Log.w(TAG, "Unable to load service info " + resolveInfo.toString());
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index b238d77..f652f85 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -73,6 +73,10 @@
      * @hide
      */
     public static final String KEY_NEGATIVE_TEXT = "negative_text";
+    /**
+     * @hide
+     */
+    public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation";
 
     /**
      * Error/help message will show for this amount of time.
@@ -215,6 +219,30 @@
         }
 
         /**
+         * Optional: A hint to the system to require user confirmation after a biometric has been
+         * authenticated. For example, implicit modalities like Face and Iris authentication are
+         * passive, meaning they don't require an explicit user action to complete. When set to
+         * 'false', the user action (e.g. pressing a button) will not be required. BiometricPrompt
+         * will require confirmation by default.
+         *
+         * A typical use case for not requiring confirmation would be for low-risk transactions,
+         * such as re-authenticating a recently authenticated application. A typical use case for
+         * requiring confirmation would be for authorizing a purchase.
+         *
+         * Note that this is a hint to the system. The system may choose to ignore the flag. For
+         * example, if the user disables implicit authentication in Settings, or if it does not
+         * apply to a modality (e.g. Fingerprint). When ignored, the system will default to
+         * requiring confirmation.
+         *
+         * @param requireConfirmation
+         * @hide
+         */
+        public Builder setRequireConfirmation(boolean requireConfirmation) {
+            mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation);
+            return this;
+        }
+
+        /**
          * Creates a {@link BiometricPrompt}.
          * @return a {@link BiometricPrompt}
          * @throws IllegalArgumentException if any of the required fields are not set.
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index dd782ec..0cf2d18 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -16,7 +16,9 @@
 
 package android.hardware.display;
 
+import android.Manifest;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.IBinder;
@@ -31,6 +33,7 @@
  *
  * @hide
  */
+@SystemApi
 @SystemService(Context.COLOR_DISPLAY_SERVICE)
 public final class ColorDisplayManager {
 
@@ -48,13 +51,29 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
     public boolean isDeviceColorManaged() {
         return mManager.isDeviceColorManaged();
     }
 
     /**
+     * Set the level of color saturation to apply to the display.
+     *
+     * @param saturationLevel 0-100 (inclusive), where 100 is full saturation
+     * @return whether the saturation level change was applied successfully
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setSaturationLevel(int saturationLevel) {
+        return mManager.setSaturationLevel(saturationLevel);
+    }
+
+    /**
      * Returns {@code true} if Night Display is supported by the device.
+     *
+     * @hide
      */
     public static boolean isNightDisplayAvailable(Context context) {
         return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
@@ -62,6 +81,8 @@
 
     /**
      * Returns {@code true} if display white balance is supported by the device.
+     *
+     * @hide
      */
     public static boolean isDisplayWhiteBalanceAvailable(Context context) {
         return context.getResources().getBoolean(R.bool.config_displayWhiteBalanceAvailable);
@@ -99,5 +120,13 @@
                 throw e.rethrowFromSystemServer();
             }
         }
+
+        boolean setSaturationLevel(int saturationLevel) {
+            try {
+                return mCdm.setSaturationLevel(saturationLevel);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
     }
 }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 82e765d..44b653c 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -563,11 +563,16 @@
      * 0 produces a grayscale image, 1 is normal.
      *
      * @hide
+     * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)}.
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
     public void setSaturationLevel(float level) {
-        mGlobal.setSaturationLevel(level);
+        if (level < 0f || level > 1f) {
+            throw new IllegalArgumentException("Saturation level must be between 0 and 1");
+        }
+        final ColorDisplayManager cdm = mContext.getSystemService(ColorDisplayManager.class);
+        cdm.setSaturationLevel(Math.round(level * 100f));
     }
 
     /**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 7304ab4..cda8498 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -394,17 +394,6 @@
         }
     }
 
-    /**
-     * Set the level of color saturation to apply to the display.
-     */
-    public void setSaturationLevel(float level) {
-        try {
-            mDm.setSaturationLevel(level);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
     public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
             String name, int width, int height, int densityDpi, Surface surface, int flags,
             VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
index f786589..81b82c6 100644
--- a/core/java/android/hardware/display/IColorDisplayManager.aidl
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -19,4 +19,6 @@
 /** @hide */
 interface IColorDisplayManager {
     boolean isDeviceColorManaged();
+
+    boolean setSaturationLevel(int saturationLevel);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index b575997..2d81cdf 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -66,9 +66,6 @@
     // Requires CONFIGURE_DISPLAY_COLOR_MODE
     void requestColorMode(int displayId, int colorMode);
 
-    // Requires CONTROL_DISPLAY_SATURATION
-    void setSaturationLevel(float level);
-
     // Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
     // MediaProjection token for certain combinations of flags.
     int createVirtualDisplay(in IVirtualDisplayCallback callback,
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 1630b06..c9a7830 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -163,8 +163,8 @@
                 mAuthenticationCallback = callback;
                 mCryptoObject = crypto;
                 long sessionId = crypto != null ? crypto.getOpId() : 0;
-                mService.authenticate(mToken, sessionId, mServiceReceiver, flags,
-                        mContext.getOpPackageName());
+                mService.authenticate(mToken, sessionId, mContext.getUserId(), mServiceReceiver,
+                        flags, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.w(TAG, "Remote exception while authenticating: ", e);
                 if (callback != null) {
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index a1c88f8..f67760a 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -27,7 +27,7 @@
  */
 interface IFaceService {
     // Authenticate the given sessionId with a face
-    void authenticate(IBinder token, long sessionId,
+    void authenticate(IBinder token, long sessionId, int userid,
             IFaceServiceReceiver receiver, int flags, String opPackageName);
 
     // This method prepares the service to start authenticating, but doesn't start authentication.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 436b4a1..abc00fe 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2051,6 +2051,16 @@
         return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
+    /** @hide */
+    public NetworkRequest getDefaultRequest() {
+        try {
+            // This is not racy as the default request is final in ConnectivityService.
+            return mService.getDefaultRequest();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /* TODO: These permissions checks don't belong in client-side code. Move them to
      * services.jar, possibly in com.android.server.net. */
 
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e7d441d..da5d96e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -167,6 +167,8 @@
 
     int getMultipathPreference(in Network Network);
 
+    NetworkRequest getDefaultRequest();
+
     int getRestoreDefaultNetworkDelay(int networkType);
 
     boolean addVpnAddress(String address, int prefixLength);
diff --git a/core/java/android/net/IIpMemoryStore.aidl b/core/java/android/net/IIpMemoryStore.aidl
new file mode 100644
index 0000000..6f88dec
--- /dev/null
+++ b/core/java/android/net/IIpMemoryStore.aidl
@@ -0,0 +1,113 @@
+/*
+ * 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.net;
+
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+
+/** {@hide} */
+oneway interface IIpMemoryStore {
+    /**
+     * Store network attributes for a given L2 key.
+     * If L2Key is null, choose automatically from the attributes ; passing null is equivalent to
+     * calling findL2Key with the attributes and storing in the returned value.
+     *
+     * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+     *              key and only care about grouping can pass a unique ID here like the ones
+     *              generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+     *              relevance of such a network will lead to it being evicted soon if it's not
+     *              refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+     * @param attributes The attributes for this network.
+     * @param listener A listener that will be invoked to inform of the completion of this call,
+     *                 or null if the client is not interested in learning about success/failure.
+     * @return (through the listener) The L2 key. This is useful if the L2 key was not specified.
+     *         If the call failed, the L2 key will be null.
+     */
+    void storeNetworkAttributes(String l2Key, in NetworkAttributesParcelable attributes,
+            IOnStatusListener listener);
+
+    /**
+     * Store a binary blob associated with an L2 key and a name.
+     *
+     * @param l2Key The L2 key for this network.
+     * @param clientId The ID of the client.
+     * @param name The name of this data.
+     * @param data The data to store.
+     * @param listener A listener to inform of the completion of this call, or null if the client
+     *        is not interested in learning about success/failure.
+     * @return (through the listener) A status to indicate success or failure.
+     */
+    void storeBlob(String l2Key, String clientId, String name, in Blob data,
+            IOnStatusListener listener);
+
+    /**
+     * Returns the best L2 key associated with the attributes.
+     *
+     * This will find a record that would be in the same group as the passed attributes. This is
+     * useful to choose the key for storing a sample or private data when the L2 key is not known.
+     * If multiple records are group-close to these attributes, the closest match is returned.
+     * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+     * order) L2 key is returned.
+     * If no record matches these attributes, null is returned.
+     *
+     * @param attributes The attributes of the network to find.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) The L2 key if one matched, or null.
+     */
+    void findL2Key(in NetworkAttributesParcelable attributes, IOnL2KeyResponseListener listener);
+
+    /**
+     * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+     * to the same L3 network. Group-closeness is used to determine this.
+     *
+     * @param l2Key1 The key for the first network.
+     * @param l2Key2 The key for the second network.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) A SameL3NetworkResponse containing the answer and confidence.
+     */
+    void isSameNetwork(String l2Key1, String l2Key2, IOnSameNetworkResponseListener listener);
+
+    /**
+     * Retrieve the network attributes for a key.
+     * If no record is present for this key, this will return null attributes.
+     *
+     * @param l2Key The key of the network to query.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) The network attributes and the L2 key associated with
+     *         the query.
+     */
+    void retrieveNetworkAttributes(String l2Key, IOnNetworkAttributesRetrieved listener);
+
+    /**
+     * Retrieve previously stored private data.
+     * If no data was stored for this L2 key and name this will return null.
+     *
+     * @param l2Key The L2 key.
+     * @param clientId The id of the client that stored this data.
+     * @param name The name of the data.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) The private data (or null), with the L2 key
+     *         and the name of the data associated with the query.
+     */
+    void retrieveBlob(String l2Key, String clientId, String name,
+            IOnBlobRetrievedListener listener);
+}
diff --git a/core/java/android/net/INetworkMonitor.aidl b/core/java/android/net/INetworkMonitor.aidl
new file mode 100644
index 0000000..41f969a
--- /dev/null
+++ b/core/java/android/net/INetworkMonitor.aidl
@@ -0,0 +1,45 @@
+/**
+ * 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 perNmissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.net.PrivateDnsConfigParcel;
+
+/** @hide */
+oneway interface INetworkMonitor {
+    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
+    // The network should be used as a default internet connection.  It was found to be:
+    // 1. a functioning network providing internet access, or
+    // 2. a captive portal and the user decided to use it as is.
+    const int NETWORK_TEST_RESULT_VALID = 0;
+
+    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
+    // The network should not be used as a default internet connection.  It was found to be:
+    // 1. a captive portal and the user is prompted to sign-in, or
+    // 2. a captive portal and the user did not want to use it, or
+    // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed).
+    const int NETWORK_TEST_RESULT_INVALID = 1;
+
+    void start();
+    void launchCaptivePortalApp();
+    void forceReevaluation(int uid);
+    void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config);
+    void notifyDnsResponse(int returnCode);
+    void notifySystemReady();
+    void notifyNetworkConnected();
+    void notifyNetworkDisconnected();
+    void notifyLinkPropertiesChanged();
+    void notifyNetworkCapabilitiesChanged();
+}
\ No newline at end of file
diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl
new file mode 100644
index 0000000..0bc2575
--- /dev/null
+++ b/core/java/android/net/INetworkMonitorCallbacks.aidl
@@ -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.
+ */
+
+package android.net;
+
+import android.net.INetworkMonitor;
+import android.net.PrivateDnsConfigParcel;
+
+/** @hide */
+oneway interface INetworkMonitorCallbacks {
+    void onNetworkMonitorCreated(in INetworkMonitor networkMonitor);
+    void notifyNetworkTested(int testResult, @nullable String redirectUrl);
+    void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config);
+    void showProvisioningNotification(String action);
+    void hideProvisioningNotification();
+}
\ No newline at end of file
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index be0dc07..2df8ab7 100644
--- a/core/java/android/net/INetworkStackConnector.aidl
+++ b/core/java/android/net/INetworkStackConnector.aidl
@@ -15,6 +15,7 @@
  */
 package android.net;
 
+import android.net.INetworkMonitorCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServerCallbacks;
 
@@ -22,4 +23,5 @@
 oneway interface INetworkStackConnector {
     void makeDhcpServer(in String ifName, in DhcpServingParamsParcel params,
         in IDhcpServerCallbacks cb);
+    void makeNetworkMonitor(int netId, String name, in INetworkMonitorCallbacks cb);
 }
\ No newline at end of file
diff --git a/core/java/android/net/IpMemoryStore.java b/core/java/android/net/IpMemoryStore.java
new file mode 100644
index 0000000..b35f097
--- /dev/null
+++ b/core/java/android/net/IpMemoryStore.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 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.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * The interface for system components to access the IP memory store.
+ * @see com.android.server.net.ipmemorystore.IpMemoryStoreService
+ * @hide
+ */
+@SystemService(Context.IP_MEMORY_STORE_SERVICE)
+public class IpMemoryStore {
+    @NonNull final Context mContext;
+    @NonNull final IIpMemoryStore mService;
+
+    public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) {
+        mContext = Preconditions.checkNotNull(context, "missing context");
+        mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore");
+    }
+
+    /**
+     * Store network attributes for a given L2 key.
+     * If L2Key is null, choose automatically from the attributes ; passing null is equivalent to
+     * calling findL2Key with the attributes and storing in the returned value.
+     *
+     * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+     *              key and only care about grouping can pass a unique ID here like the ones
+     *              generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+     *              relevance of such a network will lead to it being evicted soon if it's not
+     *              refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+     * @param attributes The attributes for this network.
+     * @param listener A listener that will be invoked to inform of the completion of this call,
+     *                 or null if the client is not interested in learning about success/failure.
+     * Through the listener, returns the L2 key. This is useful if the L2 key was not specified.
+     * If the call failed, the L2 key will be null.
+     */
+    public void storeNetworkAttributes(@NonNull final String l2Key,
+            @NonNull final NetworkAttributes attributes,
+            @Nullable final IOnStatusListener listener) {
+        try {
+            mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Store a binary blob associated with an L2 key and a name.
+     *
+     * @param l2Key The L2 key for this network.
+     * @param clientId The ID of the client.
+     * @param name The name of this data.
+     * @param data The data to store.
+     * @param listener A listener to inform of the completion of this call, or null if the client
+     *        is not interested in learning about success/failure.
+     * Through the listener, returns a status to indicate success or failure.
+     */
+    public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
+            @NonNull final String name, @NonNull final Blob data,
+            @Nullable final IOnStatusListener listener) {
+        try {
+            mService.storeBlob(l2Key, clientId, name, data, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the best L2 key associated with the attributes.
+     *
+     * This will find a record that would be in the same group as the passed attributes. This is
+     * useful to choose the key for storing a sample or private data when the L2 key is not known.
+     * If multiple records are group-close to these attributes, the closest match is returned.
+     * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+     * order) L2 key is returned.
+     * If no record matches these attributes, null is returned.
+     *
+     * @param attributes The attributes of the network to find.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the L2 key if one matched, or null.
+     */
+    public void findL2Key(@NonNull final NetworkAttributes attributes,
+            @NonNull final IOnL2KeyResponseListener listener) {
+        try {
+            mService.findL2Key(attributes.toParcelable(), listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+     * to the same L3 network. Group-closeness is used to determine this.
+     *
+     * @param l2Key1 The key for the first network.
+     * @param l2Key2 The key for the second network.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, a SameL3NetworkResponse containing the answer and confidence.
+     */
+    public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
+            @NonNull final IOnSameNetworkResponseListener listener) {
+        try {
+            mService.isSameNetwork(l2Key1, l2Key2, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieve the network attributes for a key.
+     * If no record is present for this key, this will return null attributes.
+     *
+     * @param l2Key The key of the network to query.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the network attributes and the L2 key associated with
+     *         the query.
+     */
+    public void retrieveNetworkAttributes(@NonNull final String l2Key,
+            @NonNull final IOnNetworkAttributesRetrieved listener) {
+        try {
+            mService.retrieveNetworkAttributes(l2Key, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieve previously stored private data.
+     * If no data was stored for this L2 key and name this will return null.
+     *
+     * @param l2Key The L2 key.
+     * @param clientId The id of the client that stored this data.
+     * @param name The name of the data.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the private data (or null), with the L2 key
+     *         and the name of the data associated with the query.
+     */
+    public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
+            @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
+        try {
+            mService.retrieveBlob(l2Key, clientId, name, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index d4a0ec63..2eac6de 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -48,14 +48,16 @@
 public class NetworkStack {
     private static final String TAG = NetworkStack.class.getSimpleName();
 
+    public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack";
+
     @NonNull
     @GuardedBy("mPendingNetStackRequests")
-    private final ArrayList<NetworkStackRequest> mPendingNetStackRequests = new ArrayList<>();
+    private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>();
     @Nullable
     @GuardedBy("mPendingNetStackRequests")
     private INetworkStackConnector mConnector;
 
-    private interface NetworkStackRequest {
+    private interface NetworkStackCallback {
         void onNetworkStackConnected(INetworkStackConnector connector);
     }
 
@@ -77,6 +79,21 @@
         });
     }
 
+    /**
+     * Create a NetworkMonitor.
+     *
+     * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
+     */
+    public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) {
+        requestConnector(connector -> {
+            try {
+                connector.makeNetworkMonitor(network.netId, name, cb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        });
+    }
+
     private class NetworkStackConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -96,14 +113,14 @@
         ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
                 DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
 
-        final ArrayList<NetworkStackRequest> requests;
+        final ArrayList<NetworkStackCallback> requests;
         synchronized (mPendingNetStackRequests) {
             requests = new ArrayList<>(mPendingNetStackRequests);
             mPendingNetStackRequests.clear();
             mConnector = connector;
         }
 
-        for (NetworkStackRequest r : requests) {
+        for (NetworkStackCallback r : requests) {
             r.onNetworkStackConnected(connector);
         }
     }
@@ -124,7 +141,8 @@
                     "com.android.server.NetworkStackService",
                     true /* initialize */,
                     context.getClassLoader());
-            connector = (IBinder) service.getMethod("makeConnector").invoke(null);
+            connector = (IBinder) service.getMethod("makeConnector", Context.class)
+                    .invoke(null, context);
         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
             Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService");
             // TODO: crash/reboot system here ?
@@ -153,7 +171,7 @@
     }
 
     // TODO: use this method to obtain the connector when implementing network stack operations
-    private void requestConnector(@NonNull NetworkStackRequest request) {
+    private void requestConnector(@NonNull NetworkStackCallback request) {
         // TODO: PID check.
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             // Don't even attempt to obtain the connector and give a nice error message
diff --git a/core/java/android/net/PrivateDnsConfigParcel.aidl b/core/java/android/net/PrivateDnsConfigParcel.aidl
new file mode 100644
index 0000000..b52fce6
--- /dev/null
+++ b/core/java/android/net/PrivateDnsConfigParcel.aidl
@@ -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.
+ */
+
+package android.net;
+
+parcelable PrivateDnsConfigParcel {
+    String hostname;
+    String[] ips;
+}
diff --git a/core/java/android/net/ipmemorystore/Blob.aidl b/core/java/android/net/ipmemorystore/Blob.aidl
new file mode 100644
index 0000000..9dbef11
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Blob.aidl
@@ -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.
+ */
+
+package android.net.ipmemorystore;
+
+/**
+ * A blob of data opaque to the memory store. The client mutates this at its own risk,
+ * and it is strongly suggested to never do it at all and treat this as immutable.
+ * {@hide}
+ */
+parcelable Blob {
+    byte[] data;
+}
diff --git a/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl b/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
new file mode 100644
index 0000000..4926feb
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnBlobRetrievedListener {
+    /**
+     * Private data was retrieved for the L2 key and name specified.
+     * Note this does not return the client ID, as clients are expected to only ever use one ID.
+     */
+     void onBlobRetrieved(in StatusParcelable status, in String l2Key, in String name,
+             in Blob data);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl b/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
new file mode 100644
index 0000000..dea0cc4
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnL2KeyResponseListener {
+    /**
+     * The operation completed with the specified L2 key.
+     */
+     void onL2KeyResponse(in StatusParcelable status, in String l2Key);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl b/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
new file mode 100644
index 0000000..57f59a1
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnNetworkAttributesRetrieved {
+    /**
+     * Network attributes were fetched for the specified L2 key. While the L2 key will never
+     * be null, the attributes may be if no data is stored about this L2 key.
+     */
+     void onL2KeyResponse(in StatusParcelable status, in String l2Key,
+             in NetworkAttributesParcelable attributes);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl b/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
new file mode 100644
index 0000000..294bd3b
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
@@ -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.
+ */
+
+package android.net.ipmemorystore;
+
+import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnSameNetworkResponseListener {
+    /**
+     * The memory store has come up with the answer to a query that was sent.
+     */
+     void onSameNetworkResponse(in StatusParcelable status,
+             in SameL3NetworkResponseParcelable response);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnStatusListener.aidl b/core/java/android/net/ipmemorystore/IOnStatusListener.aidl
new file mode 100644
index 0000000..5d07504
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnStatusListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnStatusListener {
+    /**
+     * The operation has completed with the specified status.
+     */
+     void onComplete(in StatusParcelable status);
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/core/java/android/net/ipmemorystore/NetworkAttributes.java
new file mode 100644
index 0000000..d7e5b27
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -0,0 +1,210 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A POD object to represent attributes of a single L2 network entry.
+ * @hide
+ */
+public class NetworkAttributes {
+    private static final boolean DBG = true;
+
+    // The v4 address that was assigned to this device the last time it joined this network.
+    // This typically comes from DHCP but could be something else like static configuration.
+    // This does not apply to IPv6.
+    // TODO : add a list of v6 prefixes for the v6 case.
+    @Nullable
+    public final Inet4Address assignedV4Address;
+
+    // Optionally supplied by the client if it has an opinion on L3 network. For example, this
+    // could be a hash of the SSID + security type on WiFi.
+    @Nullable
+    public final String groupHint;
+
+    // The list of DNS server addresses.
+    @Nullable
+    public final List<InetAddress> dnsAddresses;
+
+    // The mtu on this network.
+    @Nullable
+    public final Integer mtu;
+
+    NetworkAttributes(
+            @Nullable final Inet4Address assignedV4Address,
+            @Nullable final String groupHint,
+            @Nullable final List<InetAddress> dnsAddresses,
+            @Nullable final Integer mtu) {
+        if (mtu != null && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+        this.assignedV4Address = assignedV4Address;
+        this.groupHint = groupHint;
+        this.dnsAddresses = null == dnsAddresses ? null :
+                Collections.unmodifiableList(new ArrayList<>(dnsAddresses));
+        this.mtu = mtu;
+    }
+
+    @VisibleForTesting
+    public NetworkAttributes(@NonNull final NetworkAttributesParcelable parcelable) {
+        // The call to the other constructor must be the first statement of this constructor,
+        // so everything has to be inline
+        this((Inet4Address) getByAddressOrNull(parcelable.assignedV4Address),
+                parcelable.groupHint,
+                blobArrayToInetAddressList(parcelable.dnsAddresses),
+                parcelable.mtu >= 0 ? parcelable.mtu : null);
+    }
+
+    @Nullable
+    private static InetAddress getByAddressOrNull(@Nullable final byte[] address) {
+        try {
+            return InetAddress.getByAddress(address);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+    @Nullable
+    private static List<InetAddress> blobArrayToInetAddressList(@Nullable final Blob[] blobs) {
+        if (null == blobs) return null;
+        final ArrayList<InetAddress> list = new ArrayList<>(blobs.length);
+        for (final Blob b : blobs) {
+            final InetAddress addr = getByAddressOrNull(b.data);
+            if (null != addr) list.add(addr);
+        }
+        return list;
+    }
+
+    @Nullable
+    private static Blob[] inetAddressListToBlobArray(@Nullable final List<InetAddress> addresses) {
+        if (null == addresses) return null;
+        final ArrayList<Blob> blobs = new ArrayList<>();
+        for (int i = 0; i < addresses.size(); ++i) {
+            final InetAddress addr = addresses.get(i);
+            if (null == addr) continue;
+            final Blob b = new Blob();
+            b.data = addr.getAddress();
+            blobs.add(b);
+        }
+        return blobs.toArray(new Blob[0]);
+    }
+
+    /** Converts this NetworkAttributes to a parcelable object */
+    @NonNull
+    public NetworkAttributesParcelable toParcelable() {
+        final NetworkAttributesParcelable parcelable = new NetworkAttributesParcelable();
+        parcelable.assignedV4Address =
+                (null == assignedV4Address) ? null : assignedV4Address.getAddress();
+        parcelable.groupHint = groupHint;
+        parcelable.dnsAddresses = inetAddressListToBlobArray(dnsAddresses);
+        parcelable.mtu = (null == mtu) ? -1 : mtu;
+        return parcelable;
+    }
+
+    /** @hide */
+    public static class Builder {
+        @Nullable
+        private Inet4Address mAssignedAddress;
+        @Nullable
+        private String mGroupHint;
+        @Nullable
+        private List<InetAddress> mDnsAddresses;
+        @Nullable
+        private Integer mMtu;
+
+        /**
+         * Set the assigned address.
+         * @param assignedV4Address The assigned address.
+         * @return This builder.
+         */
+        public Builder setAssignedV4Address(@Nullable final Inet4Address assignedV4Address) {
+            mAssignedAddress = assignedV4Address;
+            return this;
+        }
+
+        /**
+         * Set the group hint.
+         * @param groupHint The group hint.
+         * @return This builder.
+         */
+        public Builder setGroupHint(@Nullable final String groupHint) {
+            mGroupHint = groupHint;
+            return this;
+        }
+
+        /**
+         * Set the DNS addresses.
+         * @param dnsAddresses The DNS addresses.
+         * @return This builder.
+         */
+        public Builder setDnsAddresses(@Nullable final List<InetAddress> dnsAddresses) {
+            if (DBG && null != dnsAddresses) {
+                // Parceling code crashes if one of the addresses is null, therefore validate
+                // them when running in debug.
+                for (final InetAddress address : dnsAddresses) {
+                    if (null == address) throw new IllegalArgumentException("Null DNS address");
+                }
+            }
+            this.mDnsAddresses = dnsAddresses;
+            return this;
+        }
+
+        /**
+         * Set the MTU.
+         * @param mtu The MTU.
+         * @return This builder.
+         */
+        public Builder setMtu(@Nullable final Integer mtu) {
+            if (null != mtu && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+            mMtu = mtu;
+            return this;
+        }
+
+        /**
+         * Return the built NetworkAttributes object.
+         * @return The built NetworkAttributes object.
+         */
+        public NetworkAttributes build() {
+            return new NetworkAttributes(mAssignedAddress, mGroupHint, mDnsAddresses, mMtu);
+        }
+    }
+
+    @Override
+    public boolean equals(@Nullable final Object o) {
+        if (!(o instanceof NetworkAttributes)) return false;
+        final NetworkAttributes other = (NetworkAttributes) o;
+        return Objects.equals(assignedV4Address, other.assignedV4Address)
+                && Objects.equals(groupHint, other.groupHint)
+                && Objects.equals(dnsAddresses, other.dnsAddresses)
+                && Objects.equals(mtu, other.mtu);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
+    }
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
new file mode 100644
index 0000000..0894d72
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.net.ipmemorystore;
+
+// Blob[] is used to represent an array of byte[], as structured AIDL does not support arrays
+// of arrays.
+import android.net.ipmemorystore.Blob;
+
+/**
+ * An object to represent attributes of a single L2 network entry.
+ * See NetworkAttributes.java for a description of each field. The types used in this class
+ * are structured parcelable types instead of the richer types of the NetworkAttributes object,
+ * but they have the same purpose. The NetworkAttributes.java file also contains the code
+ * to convert the richer types to the parcelable types and back.
+ * @hide
+ */
+parcelable NetworkAttributesParcelable {
+    byte[] assignedV4Address;
+    String groupHint;
+    Blob[] dnsAddresses;
+    int mtu;
+}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
new file mode 100644
index 0000000..0cb37e9
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
@@ -0,0 +1,131 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * An object representing the answer to a query whether two given L2 networks represent the
+ * same L3 network. Parcels as a SameL3NetworkResponseParceled object.
+ * @hide
+ */
+public class SameL3NetworkResponse {
+    @IntDef(prefix = "NETWORK_",
+            value = {NETWORK_SAME, NETWORK_DIFFERENT, NETWORK_NEVER_CONNECTED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NetworkSameness {}
+
+    /**
+     * Both L2 networks represent the same L3 network.
+     */
+    public static final int NETWORK_SAME = 1;
+
+    /**
+     * The two L2 networks represent a different L3 network.
+     */
+    public static final int NETWORK_DIFFERENT = 2;
+
+    /**
+     * The device has never connected to at least one of these two L2 networks, or data
+     * has been wiped. Therefore the device has never seen the L3 network behind at least
+     * one of these two L2 networks, and can't evaluate whether it's the same as the other.
+     */
+    public static final int NETWORK_NEVER_CONNECTED = 3;
+
+    /**
+     * The first L2 key specified in the query.
+     */
+    @NonNull
+    public final String l2Key1;
+
+    /**
+     * The second L2 key specified in the query.
+     */
+    @NonNull
+    public final String l2Key2;
+
+    /**
+     * A confidence value indicating whether the two L2 networks represent the same L3 network.
+     *
+     * If both L2 networks were known, this value will be between 0.0 and 1.0, with 0.0
+     * representing complete confidence that the given L2 networks represent a different
+     * L3 network, and 1.0 representing complete confidence that the given L2 networks
+     * represent the same L3 network.
+     * If at least one of the L2 networks was not known, this value will be outside of the
+     * 0.0~1.0 range.
+     *
+     * Most apps should not be interested in this, and are encouraged to use the collapsing
+     * {@link #getNetworkSameness()} function below.
+     */
+    public final float confidence;
+
+    /**
+     * @return whether the two L2 networks represent the same L3 network. Either
+     *     {@code NETWORK_SAME}, {@code NETWORK_DIFFERENT} or {@code NETWORK_NEVER_CONNECTED}.
+     */
+    @NetworkSameness
+    public final int getNetworkSameness() {
+        if (confidence > 1.0 || confidence < 0.0) return NETWORK_NEVER_CONNECTED;
+        return confidence > 0.5 ? NETWORK_SAME : NETWORK_DIFFERENT;
+    }
+
+    SameL3NetworkResponse(@NonNull final String l2Key1, @NonNull final String l2Key2,
+            final float confidence) {
+        this.l2Key1 = l2Key1;
+        this.l2Key2 = l2Key2;
+        this.confidence = confidence;
+    }
+
+    /** Builds a SameL3NetworkResponse from a parcelable object */
+    @VisibleForTesting
+    public SameL3NetworkResponse(@NonNull final SameL3NetworkResponseParcelable parceled) {
+        this(parceled.l2Key1, parceled.l2Key2, parceled.confidence);
+    }
+
+    /** Converts this SameL3NetworkResponse to a parcelable object */
+    @NonNull
+    public SameL3NetworkResponseParcelable toParcelable() {
+        final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
+        parcelable.l2Key1 = l2Key1;
+        parcelable.l2Key2 = l2Key2;
+        parcelable.confidence = confidence;
+        return parcelable;
+    }
+
+    // Note key1 and key2 have to match each other for this to return true. If
+    // key1 matches o.key2 and the other way around this returns false.
+    @Override
+    public boolean equals(@Nullable final Object o) {
+        if (!(o instanceof SameL3NetworkResponse)) return false;
+        final SameL3NetworkResponse other = (SameL3NetworkResponse) o;
+        return l2Key1.equals(other.l2Key1) && l2Key2.equals(other.l2Key2)
+                && confidence == other.confidence;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(l2Key1, l2Key2, confidence);
+    }
+}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl b/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
new file mode 100644
index 0000000..7196699
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.net.ipmemorystore;
+
+/** {@hide} */
+parcelable SameL3NetworkResponseParcelable {
+    String l2Key1;
+    String l2Key2;
+    float confidence;
+}
diff --git a/core/java/android/net/ipmemorystore/Status.java b/core/java/android/net/ipmemorystore/Status.java
new file mode 100644
index 0000000..5b016ec
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Status.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.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/**
+ * A parcelable status representing the result of an operation.
+ * Parcels as StatusParceled.
+ * @hide
+ */
+public class Status {
+    public static final int SUCCESS = 0;
+
+    public final int resultCode;
+
+    public Status(final int resultCode) {
+        this.resultCode = resultCode;
+    }
+
+    Status(@NonNull final StatusParcelable parcelable) {
+        this(parcelable.resultCode);
+    }
+
+    /** Converts this Status to a parcelable object */
+    @NonNull
+    public StatusParcelable toParcelable() {
+        final StatusParcelable parcelable = new StatusParcelable();
+        parcelable.resultCode = resultCode;
+        return parcelable;
+    }
+
+    public boolean isSuccess() {
+        return SUCCESS == resultCode;
+    }
+}
diff --git a/core/java/android/net/ipmemorystore/StatusParcelable.aidl b/core/java/android/net/ipmemorystore/StatusParcelable.aidl
new file mode 100644
index 0000000..fb36ef4
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/StatusParcelable.aidl
@@ -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.
+ */
+
+package android.net.ipmemorystore;
+
+/** {@hide} */
+parcelable StatusParcelable {
+  int resultCode;
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
new file mode 100644
index 0000000..1343d24
--- /dev/null
+++ b/core/java/android/os/BugreportManager.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.IBinder.DeathRecipient;
+
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class that provides a privileged API to capture and consume bugreports.
+ *
+ * @hide
+ */
+// TODO: Expose API when the implementation is more complete.
+// @SystemApi
+@SystemService(Context.BUGREPORT_SERVICE)
+public class BugreportManager {
+    private final Context mContext;
+    private final IDumpstate mBinder;
+
+    /** @hide */
+    public BugreportManager(@NonNull Context context, IDumpstate binder) {
+        mContext = context;
+        mBinder = binder;
+    }
+
+    /**
+     * An interface describing the listener for bugreport progress and status.
+     */
+    public interface BugreportListener {
+        /**
+         * Called when there is a progress update.
+         * @param progress the progress in [0.0, 100.0]
+         */
+        void onProgress(float progress);
+
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
+                BUGREPORT_ERROR_INVALID_INPUT,
+                BUGREPORT_ERROR_RUNTIME
+        })
+
+        /** Possible error codes taking a bugreport can encounter */
+        @interface BugreportErrorCode {}
+
+        /** The input options were invalid */
+        int BUGREPORT_ERROR_INVALID_INPUT = 1;
+
+        /** A runtime error occured */
+        int BUGREPORT_ERROR_RUNTIME = 2;
+
+        /**
+         * Called when taking bugreport resulted in an error.
+         *
+         * @param errorCode the error that occurred. Possible values are
+         *     {@code BUGREPORT_ERROR_INVALID_INPUT}, {@code BUGREPORT_ERROR_RUNTIME}.
+         */
+        void onError(@BugreportErrorCode int errorCode);
+
+        /**
+         * Called when taking bugreport finishes successfully
+         *
+         * @param durationMs time capturing bugreport took in milliseconds
+         * @param title title for the bugreport; helpful in reminding the user why they took it
+         * @param description detailed description for the bugreport
+         */
+        void onFinished(long durationMs, @NonNull String title,
+                @NonNull String description);
+    }
+
+    /**
+     * Starts a bugreport asynchronously.
+     *
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only,
+     *     append mode.
+     * @param screenshotFd file to write the screenshot, if necessary. This should be opened
+     *     in write-only, append mode.
+     * @param params options that specify what kind of a bugreport should be taken
+     * @param listener callback for progress and status updates
+     */
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void startBugreport(@NonNull FileDescriptor bugreportFd,
+            @Nullable FileDescriptor screenshotFd,
+            @NonNull BugreportParams params, @Nullable BugreportListener listener) {
+        // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
+        DumpstateListener dsListener = new DumpstateListener(listener);
+
+        try {
+            mBinder.startBugreport(bugreportFd, screenshotFd, params.getMode(), dsListener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+
+    // TODO(b/111441001) Connect up with BugreportListener methods.
+    private final class DumpstateListener extends IDumpstateListener.Stub
+            implements DeathRecipient {
+        private final BugreportListener mListener;
+
+        DumpstateListener(@Nullable BugreportListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void binderDied() {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
+        public void onProgressUpdated(int progress) throws RemoteException {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
+        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
+        public void onSectionComplete(String title, int status, int size, int durationMs)
+                throws RemoteException {
+            // TODO(b/111441001): implement
+        }
+    }
+}
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
new file mode 100644
index 0000000..4e696ae
--- /dev/null
+++ b/core/java/android/os/BugreportParams.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Parameters that specify what kind of bugreport should be taken.
+ *
+ * @hide
+ */
+// TODO: Expose API when the implementation is more complete.
+// @SystemApi
+public final class BugreportParams {
+    private final int mMode;
+
+    public BugreportParams(@BugreportMode int mode) {
+        mMode = mode;
+    }
+
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
+     * Defines acceptable types of bugreports.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "BUGREPORT_MODE_" }, value = {
+            BUGREPORT_MODE_FULL,
+            BUGREPORT_MODE_INTERACTIVE,
+            BUGREPORT_MODE_REMOTE,
+            BUGREPORT_MODE_WEAR,
+            BUGREPORT_MODE_TELEPHONY,
+            BUGREPORT_MODE_WIFI
+    })
+    public @interface BugreportMode {}
+
+    /**
+     * Options for a bugreport without user interference (and hence causing less
+     * interference to the system), but includes all sections.
+     */
+    public static final int BUGREPORT_MODE_FULL = IDumpstate.BUGREPORT_MODE_FULL;
+
+    /**
+     * Options that allow user to monitor progress and enter additional data; might not
+     * include all sections.
+     */
+    public static final int BUGREPORT_MODE_INTERACTIVE = IDumpstate.BUGREPORT_MODE_INTERACTIVE;
+
+    /**
+     * Options for a bugreport requested remotely by administrator of the Device Owner app,
+     * not the device's user.
+     */
+    public static final int BUGREPORT_MODE_REMOTE = IDumpstate.BUGREPORT_MODE_REMOTE;
+
+    /**
+     * Options for a bugreport on a wearable device.
+     */
+    public static final int BUGREPORT_MODE_WEAR = IDumpstate.BUGREPORT_MODE_WEAR;
+
+    /**
+     * Options for a lightweight version of bugreport that only includes a few, urgent
+     * sections used to report telephony bugs.
+     */
+    public static final int BUGREPORT_MODE_TELEPHONY = IDumpstate.BUGREPORT_MODE_TELEPHONY;
+
+    /**
+     * Options for a lightweight bugreport that only includes a few sections related to
+     * Wifi.
+     */
+    public static final int BUGREPORT_MODE_WIFI = IDumpstate.BUGREPORT_MODE_WIFI;
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index cc6bb12..b9cdcc0 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -899,6 +899,33 @@
     }
 
     /**
+     * Flatten an {@link ArrayMap} with string keys containing a particular object
+     * type into the parcel at the current dataPosition() and growing dataCapacity()
+     * if needed. The type of the objects in the array must be one that implements
+     * Parcelable. Only the raw data of the objects is written and not their type,
+     * so you must use the corresponding {@link #createTypedArrayMap(Parcelable.Creator)}
+     *
+     * @param val The map of objects to be written.
+     * @param parcelableFlags The parcelable flags to use.
+     *
+     * @see #createTypedArrayMap(Parcelable.Creator)
+     * @see Parcelable
+     */
+    public <T extends Parcelable> void writeTypedArrayMap(@Nullable ArrayMap<String, T> val,
+            int parcelableFlags) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        final int count = val.size();
+        writeInt(count);
+        for (int i = 0; i < count; i++) {
+            writeString(val.keyAt(i));
+            writeTypedObject(val.valueAt(i), parcelableFlags);
+        }
+    }
+
+    /**
      * Write an array set to the parcel.
      *
      * @param val The array set to write.
@@ -1001,7 +1028,7 @@
      * values are written using {@link #writeValue} and must follow the
      * specification there.
      */
-    public final void writeSparseArray(@Nullable SparseArray<Object> val) {
+    public final <T> void writeSparseArray(@Nullable SparseArray<T> val) {
         if (val == null) {
             writeInt(-1);
             return;
@@ -1400,6 +1427,34 @@
     }
 
     /**
+     * Flatten a {@link SparseArray} containing a particular object type into the parcel
+     * at the current dataPosition() and growing dataCapacity() if needed. The
+     * type of the objects in the array must be one that implements Parcelable.
+     * Unlike the generic {@link #writeSparseArray(SparseArray)} method, however, only
+     * the raw data of the objects is written and not their type, so you must use the
+     * corresponding {@link #createTypedSparseArray(Parcelable.Creator)}.
+     *
+     * @param val The list of objects to be written.
+     * @param parcelableFlags The parcelable flags to use.
+     *
+     * @see #createTypedSparseArray(Parcelable.Creator)
+     * @see Parcelable
+     */
+    public final <T extends Parcelable> void writeTypedSparseArray(@Nullable SparseArray<T> val,
+            int parcelableFlags) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        final int count = val.size();
+        writeInt(count);
+        for (int i = 0; i < count; i++) {
+            writeInt(val.keyAt(i));
+            writeTypedObject(val.valueAt(i), parcelableFlags);
+        }
+    }
+
+    /**
      * @hide
      */
     public <T extends Parcelable> void writeTypedList(@Nullable List<T> val, int parcelableFlags) {
@@ -2369,7 +2424,7 @@
      * Parcelables.
      */
     @Nullable
-    public final SparseArray readSparseArray(@Nullable ClassLoader loader) {
+    public final <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) {
         int N = readInt();
         if (N < 0) {
             return null;
@@ -2466,6 +2521,62 @@
     }
 
     /**
+     * Read into a new {@link SparseArray} items containing a particular object type
+     * that were written with {@link #writeTypedSparseArray(SparseArray, int)} at the
+     * current dataPosition().  The list <em>must</em> have previously been written
+     * via {@link #writeTypedSparseArray(SparseArray, int)} with the same object type.
+     *
+     * @param creator The creator to use when for instantiation.
+     *
+     * @return A newly created {@link SparseArray} containing objects with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeTypedSparseArray(SparseArray, int)
+     */
+    public final @Nullable <T extends Parcelable> SparseArray<T> createTypedSparseArray(
+            @NonNull Parcelable.Creator<T> creator) {
+        final int count = readInt();
+        if (count < 0) {
+            return null;
+        }
+        final SparseArray<T> array = new SparseArray<>(count);
+        for (int i = 0; i < count; i++) {
+            final int index = readInt();
+            final T value = readTypedObject(creator);
+            array.append(index, value);
+        }
+        return array;
+    }
+
+    /**
+     * Read into a new {@link ArrayMap} with string keys items containing a particular
+     * object type that were written with {@link #writeTypedArrayMap(ArrayMap, int)} at the
+     * current dataPosition().  The list <em>must</em> have previously been written
+     * via {@link #writeTypedArrayMap(ArrayMap, int)} with the same object type.
+     *
+     * @param creator The creator to use when for instantiation.
+     *
+     * @return A newly created {@link ArrayMap} containing objects with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeTypedArrayMap(ArrayMap, int)
+     */
+    public final @Nullable <T extends Parcelable> ArrayMap<String, T> createTypedArrayMap(
+            @NonNull Parcelable.Creator<T> creator) {
+        final int count = readInt();
+        if (count < 0) {
+            return null;
+        }
+        final ArrayMap<String, T> map = new ArrayMap<>(count);
+        for (int i = 0; i < count; i++) {
+            final String key = readString();
+            final T value = readTypedObject(creator);
+            map.append(key, value);
+        }
+        return map;
+    }
+
+    /**
      * Read and return a new ArrayList containing String objects from
      * the parcel that was written with {@link #writeStringList} at the
      * current dataPosition().  Returns null if the
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c3e0489..0942d97 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1326,7 +1326,7 @@
      * @return Battery saver state data.
      *
      * @hide
-     * @see com.android.server.power.BatterySaverPolicy
+     * @see com.android.server.power.batterysaver.BatterySaverPolicy
      * @see PowerSaveState
      */
     public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index de1128df..4918ad1 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -27,7 +27,7 @@
     /**
      * Whether we should enable battery saver for this service.
      *
-     * @see com.android.server.power.BatterySaverPolicy
+     * @see com.android.server.power.batterysaver.BatterySaverPolicy
      */
     public final boolean batterySaverEnabled;
     /**
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 9801406..68d6d85 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.annotation.NonNull;
+
 import com.android.internal.os.Zygote;
 
 import dalvik.annotation.optimization.FastNative;
@@ -313,7 +315,7 @@
      * @param sectionName The name of the code section to appear in the trace.  This may be at
      * most 127 Unicode code units long.
      */
-    public static void beginSection(String sectionName) {
+    public static void beginSection(@NonNull String sectionName) {
         if (isTagEnabled(TRACE_TAG_APP)) {
             if (sectionName.length() > MAX_SECTION_NAME_LEN) {
                 throw new IllegalArgumentException("sectionName is too long");
@@ -345,7 +347,7 @@
      * @param methodName The method name to appear in the trace.
      * @param cookie Unique identifier for distinguishing simultaneous events
      */
-    public static void beginAsyncSection(String methodName, int cookie) {
+    public static void beginAsyncSection(@NonNull String methodName, int cookie) {
         asyncTraceBegin(TRACE_TAG_APP, methodName, cookie);
     }
 
@@ -357,7 +359,7 @@
      * @param methodName The method name to appear in the trace.
      * @param cookie Unique identifier for distinguishing simultaneous events
      */
-    public static void endAsyncSection(String methodName, int cookie) {
+    public static void endAsyncSection(@NonNull String methodName, int cookie) {
         asyncTraceEnd(TRACE_TAG_APP, methodName, cookie);
     }
 
@@ -367,7 +369,7 @@
      * @param counterName The counter name to appear in the trace.
      * @param counterValue The counter value.
      */
-    public static void setCounter(String counterName, long counterValue) {
+    public static void setCounter(@NonNull String counterName, long counterValue) {
         if (isTagEnabled(TRACE_TAG_APP)) {
             nativeTraceCounter(TRACE_TAG_APP, counterName, counterValue);
         }
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index b5aeba0..226d1d0 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -74,10 +74,13 @@
     private final String mPackageName;
     // The default vibration intensity level for haptic feedback.
     @VibrationIntensity
-    private final int mDefaultHapticFeedbackIntensity;
+    private int mDefaultHapticFeedbackIntensity;
     // The default vibration intensity level for notifications.
     @VibrationIntensity
-    private final int mDefaultNotificationVibrationIntensity;
+    private int mDefaultNotificationVibrationIntensity;
+    // The default vibration intensity level for ringtones.
+    @VibrationIntensity
+    private int mDefaultRingVibrationIntensity;
 
     /**
      * @hide to prevent subclassing from outside of the framework
@@ -85,10 +88,7 @@
     public Vibrator() {
         mPackageName = ActivityThread.currentPackageName();
         final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
-        mDefaultHapticFeedbackIntensity = loadDefaultIntensity(ctx,
-                com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
-        mDefaultNotificationVibrationIntensity = loadDefaultIntensity(ctx,
-                com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+        loadVibrationIntensities(ctx);
     }
 
     /**
@@ -96,10 +96,16 @@
      */
     protected Vibrator(Context context) {
         mPackageName = context.getOpPackageName();
+        loadVibrationIntensities(context);
+    }
+
+    private void loadVibrationIntensities(Context context) {
         mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context,
                 com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
         mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context,
                 com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+        mDefaultRingVibrationIntensity = loadDefaultIntensity(context,
+                com.android.internal.R.integer.config_defaultRingVibrationIntensity);
     }
 
     private int loadDefaultIntensity(Context ctx, int resId) {
@@ -115,13 +121,20 @@
     }
 
     /**
-     * Get the default vibration intensity for notifications and ringtones.
+     * Get the default vibration intensity for notifications.
      * @hide
      */
     public int getDefaultNotificationVibrationIntensity() {
         return mDefaultNotificationVibrationIntensity;
     }
 
+    /** Get the default vibration intensity for ringtones.
+     * @hide
+     */
+    public int getDefaultRingVibrationIntensity() {
+        return mDefaultRingVibrationIntensity;
+    }
+
     /**
      * Check whether the hardware has a vibrator.
      *
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index e21a660..d7332ae 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -45,6 +45,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
 import com.android.internal.infra.AbstractRemoteService;
 import com.android.internal.util.Preconditions;
@@ -68,6 +69,12 @@
 public final class PermissionControllerManager {
     private static final String TAG = PermissionControllerManager.class.getSimpleName();
 
+    private static final Object sLock = new Object();
+
+    /** App global remote service used by all {@link PermissionControllerManager managers} */
+    @GuardedBy("sLock")
+    private static RemoteService sRemoteService;
+
     /**
      * The key for retrieving the result from the returned bundle.
      *
@@ -140,17 +147,27 @@
     }
 
     private final @NonNull Context mContext;
-    private final RemoteService mRemoteService;
 
-    /** @hide */
+    /**
+     * Create a new {@link PermissionControllerManager}.
+     *
+     * @param context to create the manager for
+     *
+     * @hide
+     */
     public PermissionControllerManager(@NonNull Context context) {
-        Intent intent = new Intent(SERVICE_INTERFACE);
-        intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
-        ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+        synchronized (sLock) {
+            if (sRemoteService == null) {
+                Intent intent = new Intent(SERVICE_INTERFACE);
+                intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
+                ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+
+                sRemoteService = new RemoteService(context.getApplicationContext(),
+                        serviceInfo.getComponentInfo().getComponentName());
+            }
+        }
 
         mContext = context;
-        mRemoteService = new RemoteService(context,
-                serviceInfo.getComponentInfo().getComponentName());
     }
 
     /**
@@ -182,7 +199,7 @@
                     + " required");
         }
 
-        mRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(mRemoteService,
+        sRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(sRemoteService,
                 request, doDryRun, reason, mContext.getPackageName(), executor, callback));
     }
 
@@ -201,8 +218,8 @@
         checkNotNull(packageName);
         checkNotNull(callback);
 
-        mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService,
-                packageName, callback, handler == null ? mRemoteService.getHandler() : handler));
+        sRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(sRemoteService,
+                packageName, callback, handler == null ? sRemoteService.getHandler() : handler));
     }
 
     /**
@@ -219,7 +236,7 @@
         checkNotNull(packageName);
         checkNotNull(permissionName);
 
-        mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
+        sRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
                 permissionName));
     }
 
@@ -241,9 +258,9 @@
         checkCollectionElementsNotNull(permissionNames, "permissionNames");
         checkNotNull(callback);
 
-        mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService,
+        sRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(sRemoteService,
                 permissionNames, countOnlyGranted, countSystem, callback,
-                handler == null ? mRemoteService.getHandler() : handler));
+                handler == null ? sRemoteService.getHandler() : handler));
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 66e1c80..ef117ea 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -86,7 +86,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.MemoryIntArray;
-import android.view.textservice.TextServicesManager;
+import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.ColorDisplayController;
@@ -1190,7 +1190,8 @@
     /**
      * Activity Action: Show Do Not Disturb access settings.
      * <p>
-     * Users can grant and deny access to Do Not Disturb configuration from here.
+     * Users can grant and deny access to Do Not Disturb configuration from here. Managed
+     * profiles cannot grant Do Not Disturb access.
      * See {@link android.app.NotificationManager#isNotificationPolicyAccessGranted()} for more
      * details.
      * <p>
@@ -3377,6 +3378,22 @@
          */
         public static final String NOTIFICATION_VIBRATION_INTENSITY =
                 "notification_vibration_intensity";
+        /**
+         * The intensity of ringtone vibrations, if configurable.
+         *
+         * Not all devices are capable of changing their vibration intensity; on these devices
+         * there will likely be no difference between the various vibration intensities except for
+         * intensity 0 (off) and the rest.
+         *
+         * <b>Values:</b><br/>
+         * 0 - Vibration is disabled<br/>
+         * 1 - Weak vibrations<br/>
+         * 2 - Medium vibrations<br/>
+         * 3 - Strong vibrations
+         * @hide
+         */
+        public static final String RING_VIBRATION_INTENSITY =
+                "ring_vibration_intensity";
 
         /**
          * The intensity of haptic feedback vibrations, if configurable.
@@ -4246,6 +4263,7 @@
             ACCELEROMETER_ROTATION,
             SHOW_BATTERY_PERCENT,
             NOTIFICATION_VIBRATION_INTENSITY,
+            RING_VIBRATION_INTENSITY,
             HAPTIC_FEEDBACK_INTENSITY,
             DISPLAY_COLOR_MODE,
             ALARM_ALERT,
@@ -4397,6 +4415,7 @@
             VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
             VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+            VALIDATORS.put(RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
             VALIDATORS.put(HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
             VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
@@ -5030,10 +5049,6 @@
         public static boolean putStringForUser(@NonNull ContentResolver resolver,
                 @NonNull String name, @Nullable String value, @Nullable String tag,
                 boolean makeDefault, @UserIdInt int userHandle) {
-            if (LOCATION_MODE.equals(name)) {
-                // Map LOCATION_MODE to underlying location provider storage API
-                return setLocationModeForUser(resolver, Integer.parseInt(value), userHandle);
-            }
             if (MOVED_TO_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
                         + " to android.provider.Settings.Global");
@@ -5186,10 +5201,6 @@
         /** @hide */
         @UnsupportedAppUsage
         public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
-            if (LOCATION_MODE.equals(name)) {
-                // Map from to underlying location provider storage API to location mode
-                return getLocationModeForUser(cr, userHandle);
-            }
             String v = getStringForUser(cr, name, userHandle);
             try {
                 return v != null ? Integer.parseInt(v) : def;
@@ -5224,10 +5235,6 @@
         /** @hide */
         public static int getIntForUser(ContentResolver cr, String name, int userHandle)
                 throws SettingNotFoundException {
-            if (LOCATION_MODE.equals(name)) {
-                // Map from to underlying location provider storage API to location mode
-                return getLocationModeForUser(cr, userHandle);
-            }
             String v = getStringForUser(cr, name, userHandle);
             try {
                 return Integer.parseInt(v);
@@ -5810,9 +5817,8 @@
          * this value being present in settings.db or on ContentObserver notifications on the
          * corresponding Uri.
          *
-         * @deprecated use {@link #LOCATION_MODE} and
-         * {@link LocationManager#MODE_CHANGED_ACTION} (or
-         * {@link LocationManager#PROVIDERS_CHANGED_ACTION})
+         * @deprecated Providers should not be controlled individually. See {@link #LOCATION_MODE}
+          * documentation for information on reading/writing location information.
          */
         @Deprecated
         public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
@@ -5830,9 +5836,7 @@
          * notifications for the corresponding Uri. Use {@link LocationManager#MODE_CHANGED_ACTION}
          * to receive changes in this value.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated To check location mode, use {@link LocationManager#isLocationEnabled()}.
          */
         @Deprecated
         public static final String LOCATION_MODE = "location_mode";
@@ -5861,9 +5865,7 @@
         /**
          * Location access disabled.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated See {@link #LOCATION_MODE}.
          */
         @Deprecated
         public static final int LOCATION_MODE_OFF = 0;
@@ -5883,9 +5885,7 @@
          * with {@link android.location.Criteria#POWER_HIGH} may be downgraded to
          * {@link android.location.Criteria#POWER_MEDIUM}.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated See {@link #LOCATION_MODE}.
          */
         @Deprecated
         public static final int LOCATION_MODE_BATTERY_SAVING = 2;
@@ -5893,9 +5893,7 @@
         /**
          * Best-effort location computation allowed.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated See {@link #LOCATION_MODE}.
          */
         @Deprecated
         public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
@@ -6019,6 +6017,15 @@
                 "lock_screen_allow_remote_input";
 
         /**
+         * Indicates which clock face to show on lock screen and AOD.
+         * @hide
+         */
+        public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face";
+
+        private static final Validator LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR =
+                ANY_STRING_VALIDATOR;
+
+        /**
          * Set by the system to track if the user needs to see the call to action for
          * the lockscreen notification policy.
          * @hide
@@ -7835,6 +7842,19 @@
                 BOOLEAN_VALIDATOR;
 
         /**
+         * Whether or not face unlock always requires user confirmation, meaning {@link
+         * android.hardware.biometrics.BiometricPrompt.Builder#setRequireConfirmation(boolean)}
+         * is always 'true'. This overrides the behavior that apps choose in the
+         * setRequireConfirmation API.
+         * @hide
+         */
+        public static final String FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
+                "face_unlock_always_require_confirmation";
+
+        private static final Validator FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR =
+                BOOLEAN_VALIDATOR;
+
+        /**
          * Whether the assist gesture should be enabled.
          *
          * @hide
@@ -8431,6 +8451,7 @@
             AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
             FACE_UNLOCK_KEYGUARD_ENABLED,
             FACE_UNLOCK_APP_ENABLED,
+            FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
             ASSIST_GESTURE_ENABLED,
             ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
             ASSIST_GESTURE_WAKE_ENABLED,
@@ -8448,6 +8469,7 @@
             HUSH_GESTURE_USED,
             IN_CALL_NOTIFICATION_ENABLED,
             LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+            LOCK_SCREEN_CUSTOM_CLOCK_FACE,
             LOCK_SCREEN_SHOW_NOTIFICATIONS,
             ZEN_DURATION,
             SHOW_ZEN_UPGRADE_NOTIFICATION,
@@ -8584,6 +8606,8 @@
                     AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
             VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR);
             VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
+            VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+                    FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
                     ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
@@ -8624,6 +8648,7 @@
             VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
             VALIDATORS.put(TRUST_AGENTS_EXTEND_UNLOCK, TRUST_AGENTS_EXTEND_UNLOCK_VALIDATOR);
+            VALIDATORS.put(LOCK_SCREEN_CUSTOM_CLOCK_FACE, LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR);
             VALIDATORS.put(LOCK_SCREEN_WHEN_TRUST_LOST, LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR);
         }
 
@@ -8652,14 +8677,14 @@
             CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED);
             CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION);
             CLONE_TO_MANAGED_PROFILE.add(ALLOWED_GEOLOCATION_ORIGINS);
-            CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
             CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
-            CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
             CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
-            if (TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER) {
+            if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+                CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
+                CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
                 CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
                 CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
             }
@@ -8778,84 +8803,6 @@
                         userId);
             }
         }
-
-        /**
-         * Thread-safe method for setting the location mode to one of
-         * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
-         * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
-         * Necessary because the mode is a composite of the underlying location provider
-         * settings.
-         *
-         * @param cr the content resolver to use
-         * @param mode such as {@link #LOCATION_MODE_HIGH_ACCURACY}
-         * @param userId the userId for which to change mode
-         * @return true if the value was set, false on database errors
-         *
-         * @throws IllegalArgumentException if mode is not one of the supported values
-         *
-         * @deprecated To enable/disable location, use
-         *             {@link LocationManager#setLocationEnabledForUser(boolean, int)}.
-         *             To enable/disable a specific location provider, use
-         *             {@link LocationManager#setProviderEnabledForUser(String, boolean, int)}.
-         */
-        @Deprecated
-        private static boolean setLocationModeForUser(
-                ContentResolver cr, int mode, int userId) {
-            synchronized (mLocationSettingsLock) {
-                boolean gps = false;
-                boolean network = false;
-                switch (mode) {
-                    case LOCATION_MODE_OFF:
-                        break;
-                    case LOCATION_MODE_SENSORS_ONLY:
-                        gps = true;
-                        break;
-                    case LOCATION_MODE_BATTERY_SAVING:
-                        network = true;
-                        break;
-                    case LOCATION_MODE_HIGH_ACCURACY:
-                        gps = true;
-                        network = true;
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Invalid location mode: " + mode);
-                }
-
-                boolean nlpSuccess = Settings.Secure.setLocationProviderEnabledForUser(
-                        cr, LocationManager.NETWORK_PROVIDER, network, userId);
-                boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
-                        cr, LocationManager.GPS_PROVIDER, gps, userId);
-                return gpsSuccess && nlpSuccess;
-            }
-        }
-
-        /**
-         * Thread-safe method for reading the location mode, returns one of
-         * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
-         * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}. Necessary
-         * because the mode is a composite of the underlying location provider settings.
-         *
-         * @param cr the content resolver to use
-         * @param userId the userId for which to read the mode
-         * @return the location mode
-         */
-        private static final int getLocationModeForUser(ContentResolver cr, int userId) {
-            synchronized (mLocationSettingsLock) {
-                boolean gpsEnabled = Settings.Secure.isLocationProviderEnabledForUser(
-                        cr, LocationManager.GPS_PROVIDER, userId);
-                boolean networkEnabled = Settings.Secure.isLocationProviderEnabledForUser(
-                        cr, LocationManager.NETWORK_PROVIDER, userId);
-                if (gpsEnabled && networkEnabled) {
-                    return LOCATION_MODE_HIGH_ACCURACY;
-                } else if (gpsEnabled) {
-                    return LOCATION_MODE_SENSORS_ONLY;
-                } else if (networkEnabled) {
-                    return LOCATION_MODE_BATTERY_SAVING;
-                } else {
-                    return LOCATION_MODE_OFF;
-                }
-            }
-        }
     }
 
     /**
@@ -9423,8 +9370,7 @@
                 "hdmi_control_auto_wakeup_enabled";
 
         /**
-         * Whether TV or Audio System will also turn off other CEC devices when it goes to standby
-         * mode.
+         * Whether TV will also turn off other CEC devices when it goes to standby mode.
          * (0 = false, 1 = true)
          *
          * @hide
@@ -9433,15 +9379,6 @@
                 "hdmi_control_auto_device_off_enabled";
 
         /**
-         * Whether Audio System will also turn off TV when it goes to standby mode.
-         * (0 = false, 1 = true)
-         *
-         * @hide
-         */
-        public static final String HDMI_CONTROL_AUTO_TV_OFF_ENABLED =
-                "hdmi_control_auto_tv_off_enabled";
-
-        /**
          * If <b>true</b>, enables out-of-the-box execution for priv apps.
          * Default: false
          * Values: 0 = false, 1 = true
@@ -11272,14 +11209,14 @@
          * quick_doze_enabled                (boolean)
          * </pre>
          * @hide
-         * @see com.android.server.power.BatterySaverPolicy
+         * @see com.android.server.power.batterysaver.BatterySaverPolicy
          */
         public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
 
         /**
          * Battery Saver device specific settings
          * This is encoded as a key=value list, separated by commas.
-         * See {@link com.android.server.power.BatterySaverPolicy} for the details.
+         * See {@link com.android.server.power.batterysaver.BatterySaverPolicy} for the details.
          *
          * @hide
          */
@@ -13836,6 +13773,7 @@
          * requires_targeting_p            (boolean)
          * max_squeeze_remeasure_attempts  (int)
          * edit_choices_before_sending     (boolean)
+         * show_in_heads_up                (boolean)
          * </pre>
          * @see com.android.systemui.statusbar.policy.SmartReplyConstants
          * @hide
@@ -14020,6 +13958,53 @@
          */
         public static final String NATIVE_FLAGS_HEALTH_CHECK_ENABLED =
                 "native_flags_health_check_enabled";
+
+        /**
+         * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls the mode
+         * in which the historical registry operates.
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_MODE = "mode";
+
+        /**
+         * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls how long
+         * is the interval between snapshots in the base case i.e. the most recent
+         * part of the history.
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_BASE_INTERVAL_MILLIS = "baseIntervalMillis";
+
+        /**
+         * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls the base
+         * for the logarithmic step when building app op history.
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_INTERVAL_MULTIPLIER = "intervalMultiplier";
+
+        /**
+         * Appop history parameters. These parameters are represented by
+         * a comma-delimited key-value list.
+         *
+         * The following strings are supported as keys:
+         * <pre>
+         *     mode                  (int)
+         *     baseIntervalMillis    (long)
+         *     intervalMultiplier    (int)
+         * </pre>
+         *
+         * Ex: "enabled=true,baseIntervalMillis=1000,intervalMultiplier=10"
+         *
+         * @see #APPOP_HISTORY_MODE
+         * @see #APPOP_HISTORY_BASE_INTERVAL_MILLIS
+         * @see #APPOP_HISTORY_INTERVAL_MULTIPLIER
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_PARAMETERS =
+                "appop_history_parameters";
     }
 
     /**
diff --git a/core/java/android/service/appprediction/AppPredictionService.java b/core/java/android/service/appprediction/AppPredictionService.java
new file mode 100644
index 0000000..b77405a
--- /dev/null
+++ b/core/java/android/service/appprediction/AppPredictionService.java
@@ -0,0 +1,322 @@
+/*
+ * 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.service.appprediction;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
+import android.app.prediction.IPredictionCallback;
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.service.appprediction.IPredictionService.Stub;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * TODO(b/111701043): Add java docs
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class AppPredictionService extends Service {
+
+    private static final String TAG = "AppPredictionService";
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     * TODO(b/111701043): Add any docs about permissions the service must hold
+     *
+     * @hide
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.appprediction.AppPredictionService";
+
+    private final ArrayMap<AppPredictionSessionId, ArrayList<CallbackWrapper>> mSessionCallbacks =
+            new ArrayMap<>();
+    private Handler mHandler;
+
+    private final IPredictionService mInterface = new Stub() {
+
+        @Override
+        public void onCreatePredictionSession(AppPredictionContext context,
+                AppPredictionSessionId sessionId) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doCreatePredictionSession,
+                            AppPredictionService.this, context, sessionId));
+        }
+
+        @Override
+        public void notifyAppTargetEvent(AppPredictionSessionId sessionId, AppTargetEvent event) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::onAppTargetEvent,
+                            AppPredictionService.this, sessionId, event));
+        }
+
+        @Override
+        public void notifyLocationShown(AppPredictionSessionId sessionId, String launchLocation,
+                ParceledListSlice targetIds) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::onLocationShown, AppPredictionService.this,
+                            sessionId, launchLocation, targetIds.getList()));
+        }
+
+        @Override
+        public void sortAppTargets(AppPredictionSessionId sessionId, ParceledListSlice targets,
+                IPredictionCallback callback) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::onSortAppTargets,
+                            AppPredictionService.this, sessionId, targets.getList(), null,
+                            new CallbackWrapper(callback)));
+        }
+
+        @Override
+        public void registerPredictionUpdates(AppPredictionSessionId sessionId,
+                IPredictionCallback callback) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doRegisterPredictionUpdates,
+                            AppPredictionService.this, sessionId, callback));
+        }
+
+        @Override
+        public void unregisterPredictionUpdates(AppPredictionSessionId sessionId,
+                IPredictionCallback callback) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doUnregisterPredictionUpdates,
+                            AppPredictionService.this, sessionId, callback));
+        }
+
+        @Override
+        public void requestPredictionUpdate(AppPredictionSessionId sessionId) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doRequestPredictionUpdate,
+                            AppPredictionService.this, sessionId));
+        }
+
+        @Override
+        public void onDestroyPredictionSession(AppPredictionSessionId sessionId) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doDestroyPredictionSession,
+                            AppPredictionService.this, sessionId));
+        }
+    };
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mInterface.asBinder();
+    }
+
+    /**
+     * Called by a client app to indicate a target launch
+     */
+    @MainThread
+    public abstract void onAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+            @NonNull AppTargetEvent event);
+
+    /**
+     * Called by a client app to indication a particular location has been shown to the user.
+     */
+    @MainThread
+    public abstract void onLocationShown(@NonNull AppPredictionSessionId sessionId,
+            @NonNull String launchLocation, @NonNull List<AppTargetId> targetIds);
+
+    private void doCreatePredictionSession(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {
+        mSessionCallbacks.put(sessionId, new ArrayList<>());
+        onCreatePredictionSession(context, sessionId);
+    }
+
+    /**
+     * Creates a new interaction session.
+     *
+     * @param context interaction context
+     * @param sessionId the session's Id
+     */
+    public void onCreatePredictionSession(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {}
+
+    /**
+     * Called by the client app to request sorting of targets based on prediction rank.
+     * TODO(b/111701043): Implement CancellationSignal so caller can cancel a long running request
+     */
+    @MainThread
+    public abstract void onSortAppTargets(@NonNull AppPredictionSessionId sessionId,
+            @NonNull List<AppTarget> targets, @NonNull CancellationSignal cancellationSignal,
+            @NonNull Consumer<List<AppTarget>> callback);
+
+    private void doRegisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks == null) {
+            Slog.e(TAG, "Failed to register for updates for unknown session: " + sessionId);
+            return;
+        }
+
+        final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
+        if (wrapper == null) {
+            callbacks.add(new CallbackWrapper(callback));
+            if (callbacks.size() == 1) {
+                onStartPredictionUpdates();
+            }
+        }
+    }
+
+    /**
+     * Called when any continuous prediction callback is registered.
+     */
+    @MainThread
+    public void onStartPredictionUpdates() {}
+
+    private void doUnregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks == null) {
+            Slog.e(TAG, "Failed to unregister for updates for unknown session: " + sessionId);
+            return;
+        }
+
+        final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
+        if (wrapper != null) {
+            callbacks.remove(wrapper);
+            if (callbacks.isEmpty()) {
+                onStopPredictionUpdates();
+            }
+        }
+    }
+
+    /**
+     * Called when there are no longer any continuous prediction callbacks registered.
+     */
+    @MainThread
+    public void onStopPredictionUpdates() {}
+
+    private void doRequestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+        final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks != null && !callbacks.isEmpty()) {
+            onRequestPredictionUpdate(sessionId);
+        }
+    }
+
+    /**
+     * Called by the client app to request target predictions. This method is only called if there
+     * are one or more prediction callbacks registered.
+     * TODO(b/111701043): Add java docs
+     *
+     * @see #updatePredictions(AppPredictionSessionId, List)
+     */
+    @MainThread
+    public abstract void onRequestPredictionUpdate(@NonNull AppPredictionSessionId sessionId);
+
+    private void doDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+        mSessionCallbacks.remove(sessionId);
+        onDestroyPredictionSession(sessionId);
+    }
+
+    /**
+     * Destroys the interaction session.
+     *
+     * @param sessionId the id of the session to destroy
+     */
+    @MainThread
+    public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {}
+
+    /**
+     * Used by the prediction factory to send back results the client app. The can be called
+     * in response to {@link #onRequestPredictionUpdate(AppPredictionSessionId)} or proactively as
+     * a result of changes in predictions.
+     */
+    public final void updatePredictions(@NonNull AppPredictionSessionId sessionId,
+            @NonNull List<AppTarget> targets) {
+        List<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks != null) {
+            for (CallbackWrapper callback : callbacks) {
+                callback.accept(targets);
+            }
+        }
+    }
+
+    /**
+     * Finds the callback wrapper for the given callback.
+     */
+    private CallbackWrapper findCallbackWrapper(ArrayList<CallbackWrapper> callbacks,
+            IPredictionCallback callback) {
+        for (int i = callbacks.size() - 1; i >= 0; i--) {
+            if (callbacks.get(i).isCallback(callback)) {
+                return callbacks.get(i);
+            }
+        }
+        return null;
+    }
+
+    private static final class CallbackWrapper implements Consumer<List<AppTarget>>,
+            IBinder.DeathRecipient {
+
+        private IPredictionCallback mCallback;
+
+        CallbackWrapper(IPredictionCallback callback) {
+            mCallback = callback;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to link to death: " + e);
+            }
+        }
+
+        public boolean isCallback(@NonNull IPredictionCallback callback) {
+            return mCallback.equals(callback);
+        }
+
+        @Override
+        public void accept(List<AppTarget> ts) {
+            try {
+                if (mCallback != null) {
+                    mCallback.onResult(new ParceledListSlice(ts));
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result:" + e);
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mCallback = null;
+        }
+    }
+}
diff --git a/core/java/android/service/appprediction/IPredictionService.aidl b/core/java/android/service/appprediction/IPredictionService.aidl
new file mode 100644
index 0000000..3a6d166
--- /dev/null
+++ b/core/java/android/service/appprediction/IPredictionService.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.service.appprediction;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.IPredictionCallback;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * Interface from the system to a prediction service.
+ *
+ * @hide
+ */
+oneway interface IPredictionService {
+
+    void onCreatePredictionSession(in AppPredictionContext context,
+            in AppPredictionSessionId sessionId);
+
+    void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
+
+    void notifyLocationShown(in AppPredictionSessionId sessionId,  in String launchLocation,
+            in ParceledListSlice targetIds);
+
+    void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
+            in IPredictionCallback callback);
+
+    void registerPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void unregisterPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void requestPredictionUpdate(in AppPredictionSessionId sessionId);
+
+    void onDestroyPredictionSession(in AppPredictionSessionId sessionId);
+}
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 26bf361..e5e028d 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -42,6 +42,7 @@
 import android.view.contentcapture.ContentCaptureSessionId;
 import android.view.contentcapture.IContentCaptureDirectManager;
 import android.view.contentcapture.MainContentCaptureSession;
+import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -165,7 +166,7 @@
      */
     public final void setContentCaptureWhitelist(@Nullable List<String> packages,
             @Nullable List<ComponentName> activities) {
-        //TODO(b/111276913): implement
+        //TODO(b/122595322): implement
     }
 
     /**
@@ -176,7 +177,7 @@
      */
     public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
             boolean enabled) {
-        //TODO(b/111276913): implement
+        //TODO(b/122595322): implement
     }
 
     /**
@@ -187,7 +188,7 @@
      */
     public final void setPackageContentCaptureEnabled(@NonNull String packageName,
             boolean enabled) {
-        //TODO(b/111276913): implement
+        //TODO(b/122595322): implement
     }
 
     /**
@@ -196,7 +197,7 @@
      */
     @NonNull
     public final Set<ComponentName> getContentCaptureDisabledActivities() {
-        //TODO(b/111276913): implement
+        //TODO(b/122595322): implement
         return null;
     }
 
@@ -206,7 +207,7 @@
      */
     @NonNull
     public final Set<String> getContentCaptureDisabledPackages() {
-        //TODO(b/111276913): implement
+        //TODO(b/122595322): implement
         return null;
     }
 
@@ -255,6 +256,16 @@
         if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
         onContentCaptureEventsRequest(sessionId, new ContentCaptureEventsRequest(event));
     }
+
+    /**
+     * Notifies the service that the app requested to remove data associated with the user.
+     *
+     * @param request the user data requested to be removed
+     */
+    public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) {
+        if (VERBOSE) Log.v(TAG, "onUserDataRemovalRequest()");
+    }
+
     /**
      * Notifies the service of {@link SnapshotData snapshot data} associated with a session.
      *
@@ -311,6 +322,14 @@
             @NonNull String sessionId, int uid, IResultReceiver clientReceiver) {
         mSessionUids.put(sessionId, uid);
         onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
+
+        final int flags = context.getFlags();
+        if ((flags & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0) {
+            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_BY_FLAG_SECURE,
+                    mClientInterface.asBinder());
+            return;
+        }
+
         setClientState(clientReceiver, ContentCaptureSession.STATE_ACTIVE,
                 mClientInterface.asBinder());
     }
@@ -392,15 +411,16 @@
     }
 
     /**
-     * Sends the state of the {@link ContentCaptureManager} in the cleint app.
+     * Sends the state of the {@link ContentCaptureManager} in the client app.
      *
      * @param clientReceiver receiver in the client app.
+     * @param sessionState state of the session
      * @param binder handle to the {@code IContentCaptureDirectManager} object that resides in the
      * service.
      * @hide
      */
     public static void setClientState(@NonNull IResultReceiver clientReceiver,
-            int sessionStatus, @Nullable IBinder binder) {
+            int sessionState, @Nullable IBinder binder) {
         try {
             final Bundle extras;
             if (binder != null) {
@@ -409,7 +429,7 @@
             } else {
                 extras = null;
             }
-            clientReceiver.send(sessionStatus, extras);
+            clientReceiver.send(sessionState, extras);
         } catch (RemoteException e) {
             Slog.w(TAG, "Error async reporting result to client: " + e);
         }
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
new file mode 100644
index 0000000..0da8039
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -0,0 +1,154 @@
+/*
+ * 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.service.contentsuggestions;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * @hide
+ */
+@SystemApi
+public abstract class ContentSuggestionsService extends Service {
+
+    private static final String TAG = ContentSuggestionsService.class.getSimpleName();
+
+    private Handler mHandler;
+
+    /**
+     * The action for the intent used to define the content suggestions service.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.contentsuggestions.ContentSuggestionsService";
+
+    private final IContentSuggestionsService mInterface = new IContentSuggestionsService.Stub() {
+        @Override
+        public void provideContextImage(int taskId, GraphicBuffer contextImage,
+                Bundle imageContextRequestExtras) {
+            mHandler.sendMessage(
+                    obtainMessage(ContentSuggestionsService::processContextImage,
+                            ContentSuggestionsService.this, taskId,
+                            Bitmap.createHardwareBitmap(contextImage),
+                            imageContextRequestExtras));
+        }
+
+        @Override
+        public void suggestContentSelections(SelectionsRequest request,
+                ISelectionsCallback callback) {
+            mHandler.sendMessage(obtainMessage(ContentSuggestionsService::suggestContentSelections,
+                    ContentSuggestionsService.this, request, wrapSelectionsCallback(callback)));
+
+        }
+
+        @Override
+        public void classifyContentSelections(ClassificationsRequest request,
+                IClassificationsCallback callback) {
+            mHandler.sendMessage(obtainMessage(ContentSuggestionsService::classifyContentSelections,
+                    ContentSuggestionsService.this, request, wrapClassificationCallback(callback)));
+        }
+
+        @Override
+        public void notifyInteraction(String requestId, Bundle interaction) {
+            mHandler.sendMessage(
+                    obtainMessage(ContentSuggestionsService::notifyInteraction,
+                            ContentSuggestionsService.this, requestId, interaction));
+        }
+    };
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+    }
+
+    /** @hide */
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mInterface.asBinder();
+        }
+        Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+        return null;
+    }
+
+    /**
+     * Called by the system to provide the snapshot for the task associated with the given
+     * {@param taskId}.
+     */
+    public abstract void processContextImage(
+            int taskId, @Nullable Bitmap contextImage, @NonNull Bundle extras);
+
+    /**
+     * Called by a client app to make a request for content selections.
+     */
+    public abstract void suggestContentSelections(@NonNull SelectionsRequest request,
+            @NonNull ContentSuggestionsManager.SelectionsCallback callback);
+
+    /**
+     * Called by a client app to classify the provided content selections.
+     */
+    public abstract void classifyContentSelections(@NonNull ClassificationsRequest request,
+            @NonNull ContentSuggestionsManager.ClassificationsCallback callback);
+
+    /**
+     * Called by a client app to report an interaction.
+     */
+    public abstract void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction);
+
+    private ContentSuggestionsManager.SelectionsCallback wrapSelectionsCallback(
+            ISelectionsCallback callback) {
+        return (statusCode, selections) -> {
+            try {
+                callback.onContentSelectionsAvailable(statusCode, selections);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result: " + e);
+            }
+        };
+    }
+
+    private ContentSuggestionsManager.ClassificationsCallback wrapClassificationCallback(
+            IClassificationsCallback callback) {
+        return ((statusCode, classifications) -> {
+            try {
+                callback.onContentClassificationsAvailable(statusCode, classifications);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result: " + e);
+            }
+        });
+    }
+}
diff --git a/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
new file mode 100644
index 0000000..1926478
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+
+/**
+ * Interface from the system to an implementation of a content suggestions service.
+ *
+ * @hide
+ */
+oneway interface IContentSuggestionsService {
+    void provideContextImage(
+            int taskId,
+            in GraphicBuffer contextImage,
+            in Bundle imageContextRequestExtras);
+    void suggestContentSelections(
+            in SelectionsRequest request,
+            in ISelectionsCallback callback);
+    void classifyContentSelections(
+            in ClassificationsRequest request,
+            in IClassificationsCallback callback);
+    void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index fd2b0fae..63fd563 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -203,7 +203,7 @@
      * @param action the action that is just clicked
      * @param source the source that provided the action, e.g. SOURCE_FROM_APP
      */
-    public void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+    public void onActionInvoked(@NonNull String key, @NonNull Notification.Action action,
             @Source int source) {
     }
 
@@ -338,7 +338,7 @@
             args.arg1 = key;
             args.arg2 = action;
             args.argi2 = source;
-            mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_CLICKED, args).sendToTarget();
+            mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_INVOKED, args).sendToTarget();
         }
     }
 
@@ -349,7 +349,7 @@
         public static final int MSG_ON_NOTIFICATION_EXPANSION_CHANGED = 4;
         public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5;
         public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6;
-        public static final int MSG_ON_ACTION_CLICKED = 7;
+        public static final int MSG_ON_ACTION_INVOKED = 7;
 
         public MyHandler(Looper looper) {
             super(looper, null, false);
@@ -419,13 +419,13 @@
                     onSuggestedReplySent(key, reply, source);
                     break;
                 }
-                case MSG_ON_ACTION_CLICKED: {
+                case MSG_ON_ACTION_INVOKED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     String key = (String) args.arg1;
                     Notification.Action action = (Notification.Action) args.arg2;
                     int source = args.argi2;
                     args.recycle();
-                    onActionClicked(key, action, source);
+                    onActionInvoked(key, action, source);
                     break;
                 }
             }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index ad10cc9..3a644d4 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -22,16 +22,21 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.metrics.LogMaker;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
 /**
  * Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
  * the status bar and any {@link android.service.notification.NotificationListenerService}s.
  */
 public class StatusBarNotification implements Parcelable {
+    static final int MAX_LOG_TAG_LENGTH = 36;
+
     @UnsupportedAppUsage
     private final String pkg;
     @UnsupportedAppUsage
@@ -56,6 +61,9 @@
 
     private Context mContext; // used for inflation & icon expansion
 
+    // Contains the basic logging data of the notification.
+    private LogMaker mLogMaker;
+
     /** @hide */
     public StatusBarNotification(String pkg, String opPkg, int id,
             String tag, int uid, int initialPid, Notification notification, UserHandle user,
@@ -381,4 +389,51 @@
         }
         return mContext;
     }
+
+    /**
+     * Returns a LogMaker that contains all basic information of the notification.
+     * @hide
+     */
+    public LogMaker getLogMaker() {
+        if (mLogMaker == null) {
+            // Initialize fields that only change on update (so a new record).
+            mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
+                .setPackageName(getPackageName())
+                .addTaggedData(MetricsEvent.NOTIFICATION_ID, getId())
+                .addTaggedData(MetricsEvent.NOTIFICATION_TAG, getTag())
+                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
+        }
+        // Reset fields that can change between updates, or are used by multiple logs.
+        return mLogMaker
+            .clearCategory()
+            .clearType()
+            .clearSubtype()
+            .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
+            .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
+                getNotification().isGroupSummary() ? 1 : 0);
+    }
+
+    private String getGroupLogTag() {
+        return shortenTag(getGroup());
+    }
+
+    private String getChannelIdLogTag() {
+        if (notification.getChannelId() == null) {
+            return null;
+        }
+        return shortenTag(notification.getChannelId());
+    }
+
+    // Make logTag with max size MAX_LOG_TAG_LENGTH.
+    // For shorter or equal tags, returns the tag.
+    // For longer tags, truncate the tag and append a hash of the full tag to
+    // fill the maximum size.
+    private String shortenTag(String logTag) {
+        if (logTag == null || logTag.length() <= MAX_LOG_TAG_LENGTH) {
+            return logTag;
+        }
+        String hash = Integer.toHexString(logTag.hashCode());
+        return logTag.substring(0, MAX_LOG_TAG_LENGTH - hash.length() - 1) + "-"
+            + hash;
+    }
 }
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 433483f7..7a58681 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
@@ -370,6 +371,7 @@
     /**
      * @return The color of the underline for that span, or 0 if there is no underline
      */
+    @ColorInt
     public int getUnderlineColor() {
         // The order here should match what is used in updateDrawState
         final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index af73a16..265b0d3 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
+
 import java.io.PrintWriter;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -250,7 +251,7 @@
                     if (value == 0 && flagsWasZero) {
                         return constNameWithoutPrefix(prefix, field);
                     }
-                    if ((flags & value) != 0) {
+                    if ((flags & value) == value) {
                         flags &= ~value;
                         res.append(constNameWithoutPrefix(prefix, field)).append('|');
                     }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 8b97e0e..0edcb3d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -22,7 +22,9 @@
 import android.text.TextUtils;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Util class to get feature flag information.
@@ -37,8 +39,11 @@
     public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
     public static final String SAFETY_HUB = "settings_safety_hub";
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
+    public static final String AOD_IMAGEWALLPAPER_ENABLED = "settings_aod_imagewallpaper_enabled";
 
     private static final Map<String, String> DEFAULT_FLAGS;
+    private static final Set<String> OBSERVABLE_FLAGS;
+
     static {
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
@@ -54,6 +59,10 @@
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(SAFETY_HUB, "false");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
+        DEFAULT_FLAGS.put(AOD_IMAGEWALLPAPER_ENABLED, "false");
+
+        OBSERVABLE_FLAGS = new HashSet<>();
+        OBSERVABLE_FLAGS.add(AOD_IMAGEWALLPAPER_ENABLED);
     }
 
     /**
@@ -90,6 +99,16 @@
      */
     public static void setEnabled(Context context, String feature, boolean enabled) {
         SystemProperties.set(FFLAG_OVERRIDE_PREFIX + feature, enabled ? "true" : "false");
+
+        // Also update Settings.Global if needed so that we can observe it via observer.
+        if (OBSERVABLE_FLAGS.contains(feature)) {
+            setObservableFlag(context, feature, enabled);
+        }
+    }
+
+    private static void setObservableFlag(Context context, String feature, boolean enabled) {
+        Settings.Global.putString(
+                context.getContentResolver(), feature, enabled ? "true" : "false");
     }
 
     /**
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a86abe5..9d3552f 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -18,6 +18,9 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Matrix;
@@ -30,6 +33,7 @@
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
+import java.lang.annotation.Retention;
 import java.util.Objects;
 
 /**
@@ -462,7 +466,7 @@
 
     /**
      * This flag indicates that the event has been generated by a gesture generator. It
-     * provides a hint to the GestureDector to not apply any touch slop.
+     * provides a hint to the GestureDetector to not apply any touch slop.
      *
      * @hide
      */
@@ -1391,6 +1395,42 @@
     };
 
     /**
+     * Classification constant: None.
+     *
+     * No additional information is available about the current motion event stream.
+     *
+     * @see #getClassification
+     */
+    public static final int CLASSIFICATION_NONE = 0;
+
+    /**
+     * Classification constant: Ambiguous gesture.
+     *
+     * The user's intent with respect to the current event stream is not yet determined.
+     * Gestural actions, such as scrolling, should be inhibited until the classification resolves
+     * to another value or the event stream ends.
+     *
+     * @see #getClassification
+     */
+    public static final int CLASSIFICATION_AMBIGUOUS_GESTURE = 1;
+
+    /**
+     * Classification constant: Deep press.
+     *
+     * The current event stream represents the user intentionally pressing harder on the screen.
+     * This classification type should be used to accelerate the long press behaviour.
+     *
+     * @see #getClassification
+     */
+    public static final int CLASSIFICATION_DEEP_PRESS = 2;
+
+    /** @hide */
+    @Retention(SOURCE)
+    @IntDef(prefix = { "CLASSIFICATION" }, value = {
+            CLASSIFICATION_NONE, CLASSIFICATION_AMBIGUOUS_GESTURE, CLASSIFICATION_DEEP_PRESS})
+    public @interface Classification {};
+
+    /**
      * Tool type constant: Unknown tool type.
      * This constant is used when the tool type is not known or is not relevant,
      * such as for a trackball or other non-pointing device.
@@ -1478,7 +1518,7 @@
 
     private static native long nativeInitialize(long nativePtr,
             int deviceId, int source, int displayId, int action, int flags, int edgeFlags,
-            int metaState, int buttonState,
+            int metaState, int buttonState, @Classification int classification,
             float xOffset, float yOffset, float xPrecision, float yPrecision,
             long downTimeNanos, long eventTimeNanos,
             int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords);
@@ -1548,6 +1588,8 @@
     @CriticalNative
     private static native void nativeSetButtonState(long nativePtr, int buttonState);
     @CriticalNative
+    private static native int nativeGetClassification(long nativePtr);
+    @CriticalNative
     private static native int nativeGetActionButton(long nativePtr);
     @CriticalNative
     private static native void nativeSetActionButton(long nativePtr, int actionButton);
@@ -1648,7 +1690,7 @@
         MotionEvent ev = obtain();
         ev.mNativePtr = nativeInitialize(ev.mNativePtr,
                 deviceId, source, displayId, action, flags, edgeFlags, metaState, buttonState,
-                0, 0, xPrecision, yPrecision,
+                CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision,
                 downTime * NS_PER_MS, eventTime * NS_PER_MS,
                 pointerCount, pointerProperties, pointerCoords);
         if (ev.mNativePtr == 0) {
@@ -1833,7 +1875,7 @@
 
             ev.mNativePtr = nativeInitialize(ev.mNativePtr,
                     deviceId, source, displayId,
-                    action, 0, edgeFlags, metaState, 0,
+                    action, 0, edgeFlags, metaState, 0 /*buttonState*/, CLASSIFICATION_NONE,
                     0, 0, xPrecision, yPrecision,
                     downTime * NS_PER_MS, eventTime * NS_PER_MS,
                     1, pp, pc);
@@ -2539,6 +2581,18 @@
     }
 
     /**
+     * Returns the classification for the current gesture.
+     * The classification may change as more events become available for the same gesture.
+     *
+     * @see #CLASSIFICATION_NONE
+     * @see #CLASSIFICATION_AMBIGUOUS_GESTURE
+     * @see #CLASSIFICATION_DEEP_PRESS
+     */
+    public @Classification int getClassification() {
+        return nativeGetClassification(mNativePtr);
+    }
+
+    /**
      * Gets which button has been modified during a press or release action.
      *
      * For actions other than {@link #ACTION_BUTTON_PRESS} and {@link #ACTION_BUTTON_RELEASE}
@@ -3172,7 +3226,7 @@
     /**
      * Adds all of the movement samples of the specified event to this one if
      * it is compatible.  To be compatible, the event must have the same device id,
-     * source, display id, action, flags, pointer count, pointer properties.
+     * source, display id, action, flags, classification, pointer count, pointer properties.
      *
      * Only applies to {@link #ACTION_MOVE} or {@link #ACTION_HOVER_MOVE} events.
      *
@@ -3194,7 +3248,9 @@
         if (nativeGetDeviceId(mNativePtr) != nativeGetDeviceId(event.mNativePtr)
                 || nativeGetSource(mNativePtr) != nativeGetSource(event.mNativePtr)
                 || nativeGetDisplayId(mNativePtr) != nativeGetDisplayId(event.mNativePtr)
-                || nativeGetFlags(mNativePtr) != nativeGetFlags(event.mNativePtr)) {
+                || nativeGetFlags(mNativePtr) != nativeGetFlags(event.mNativePtr)
+                || nativeGetClassification(mNativePtr)
+                        != nativeGetClassification(event.mNativePtr)) {
             return false;
         }
 
@@ -3282,7 +3338,7 @@
                     nativeGetDisplayId(mNativePtr),
                     nativeGetAction(mNativePtr), nativeGetFlags(mNativePtr),
                     nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
-                    nativeGetButtonState(mNativePtr),
+                    nativeGetButtonState(mNativePtr), nativeGetClassification(mNativePtr),
                     nativeGetXOffset(mNativePtr), nativeGetYOffset(mNativePtr),
                     nativeGetXPrecision(mNativePtr), nativeGetYPrecision(mNativePtr),
                     nativeGetDownTimeNanos(mNativePtr),
@@ -3376,7 +3432,7 @@
                             nativeGetDisplayId(mNativePtr),
                             newAction, nativeGetFlags(mNativePtr),
                             nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
-                            nativeGetButtonState(mNativePtr),
+                            nativeGetButtonState(mNativePtr), nativeGetClassification(mNativePtr),
                             nativeGetXOffset(mNativePtr), nativeGetYOffset(mNativePtr),
                             nativeGetXPrecision(mNativePtr), nativeGetYPrecision(mNativePtr),
                             nativeGetDownTimeNanos(mNativePtr), eventTimeNanos,
@@ -3409,6 +3465,8 @@
         }
 
         appendUnless("0", msg, ", buttonState=", MotionEvent.buttonStateToString(getButtonState()));
+        appendUnless(classificationToString(CLASSIFICATION_NONE), msg, ", classification=",
+                classificationToString(getClassification()));
         appendUnless("0", msg, ", metaState=", KeyEvent.metaStateToString(getMetaState()));
         appendUnless("0", msg, ", flags=0x", Integer.toHexString(getFlags()));
         appendUnless("0", msg, ", edgeFlags=0x", Integer.toHexString(getEdgeFlags()));
@@ -3547,6 +3605,26 @@
     }
 
     /**
+     * Returns a string that represents the symbolic name of the specified classification.
+     *
+     * @param classification The classification type.
+     * @return The symbolic name of this classification.
+     * @hide
+     */
+    public static String classificationToString(@Classification int classification) {
+        switch (classification) {
+            case CLASSIFICATION_NONE:
+                return "NONE";
+            case CLASSIFICATION_AMBIGUOUS_GESTURE:
+                return "AMBIGUOUS_GESTURE";
+            case CLASSIFICATION_DEEP_PRESS:
+                return "DEEP_PRESS";
+
+        }
+        return "NONE";
+    }
+
+    /**
      * Returns a string that represents the symbolic name of the specified tool type
      * such as "TOOL_TYPE_FINGER" or an equivalent numeric constant such as "42" if unknown.
      *
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index acad5d7..ff5120d 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -58,7 +58,7 @@
 
 /**
  * SurfaceControl
- *  @hide
+ * @hide
  */
 public class SurfaceControl implements Parcelable {
     private static final String TAG = "SurfaceControl";
@@ -186,6 +186,7 @@
 
     /**
      * Surface creation flag: Surface is created hidden
+     * @hide
      */
     @UnsupportedAppUsage
     public static final int HIDDEN = 0x00000004;
@@ -196,7 +197,7 @@
      * from another process. In particular, screenshots and VNC servers will
      * be disabled, but other measures can take place, for instance the
      * surface might not be hardware accelerated.
-     *
+     * @hide
      */
     public static final int SECURE = 0x00000080;
 
@@ -220,7 +221,7 @@
      * pixel.
      * <p>
      * In some rare situations, a non pre-multiplied surface is preferable.
-     *
+     * @hide
      */
     public static final int NON_PREMULTIPLIED = 0x00000100;
 
@@ -240,6 +241,7 @@
      * </ul>
      * If the underlying buffer lacks an alpha channel, the OPAQUE flag is effectively
      * set automatically.
+     * @hide
      */
     public static final int OPAQUE = 0x00000400;
 
@@ -248,6 +250,7 @@
      * external display sink. If a hardware-protected path is not available,
      * then this surface will not be displayed on the external sink.
      *
+     * @hide
      */
     public static final int PROTECTED_APP = 0x00000800;
 
@@ -255,6 +258,7 @@
 
     /**
      * Surface creation flag: Window represents a cursor glyph.
+     * @hide
      */
     public static final int CURSOR_WINDOW = 0x00002000;
 
@@ -262,6 +266,7 @@
      * Surface creation flag: Creates a normal surface.
      * This is the default.
      *
+     * @hide
      */
     public static final int FX_SURFACE_NORMAL   = 0x00000000;
 
@@ -271,6 +276,7 @@
      * in {@link #setAlpha}.  It is an error to lock a Dim surface, since it
      * doesn't have a backing store.
      *
+     * @hide
      */
     public static final int FX_SURFACE_DIM = 0x00020000;
 
@@ -278,12 +284,14 @@
      * Surface creation flag: Creates a container surface.
      * This surface will have no buffers and will only be used
      * as a container for other surfaces, or for its InputInfo.
+     * @hide
      */
     public static final int FX_SURFACE_CONTAINER = 0x00080000;
 
     /**
      * Mask used for FX values above.
      *
+     * @hide
      */
     public static final int FX_SURFACE_MASK = 0x000F0000;
 
@@ -309,12 +317,14 @@
     /**
      * Built-in physical display id: Main display.
      * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+     * @hide
      */
     public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
 
     /**
      * Built-in physical display id: Attached HDMI display.
      * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+     * @hide
      */
     public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
 
@@ -323,30 +333,35 @@
     /**
      * Display power mode off: used while blanking the screen.
      * Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_OFF = 0;
 
     /**
      * Display power mode doze: used while putting the screen into low power mode.
      * Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_DOZE = 1;
 
     /**
      * Display power mode normal: used while unblanking the screen.
      * Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_NORMAL = 2;
 
     /**
      * Display power mode doze: used while putting the screen into a suspended
      * low power mode.  Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_DOZE_SUSPEND = 3;
 
     /**
      * Display power mode on: used while putting the screen into a suspended
      * full power mode.  Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_ON_SUSPEND = 4;
 
@@ -366,6 +381,9 @@
         mNativeObject = nativeObject;
     }
 
+    /**
+     * @hide
+     */
     public void copyFrom(SurfaceControl other) {
         mName = other.mName;
         mWidth = other.mWidth;
@@ -375,6 +393,7 @@
 
     /**
      * Builder class for {@link SurfaceControl} objects.
+     * @hide
      */
     public static class Builder {
         private SurfaceSession mSession;
@@ -391,6 +410,7 @@
          * Begin building a SurfaceControl with a given {@link SurfaceSession}.
          *
          * @param session The {@link SurfaceSession} with which to eventually construct the surface.
+         * @hide
          */
         public Builder(SurfaceSession session) {
             mSession = session;
@@ -398,6 +418,7 @@
 
         /**
          * Construct a new {@link SurfaceControl} with the set parameters.
+         * @hide
          */
         public SurfaceControl build() {
             if (mWidth < 0 || mHeight < 0) {
@@ -416,6 +437,7 @@
          * Set a debugging-name for the SurfaceControl.
          *
          * @param name A name to identify the Surface in debugging.
+         * @hide
          */
         public Builder setName(String name) {
             mName = name;
@@ -427,6 +449,7 @@
          *
          * @param width The buffer width in pixels.
          * @param height The buffer height in pixels.
+         * @hide
          */
         public Builder setBufferSize(int width, int height) {
             if (width < 0 || height < 0) {
@@ -441,6 +464,7 @@
         /**
          * Set the pixel format of the controlled surface's buffers, using constants from
          * {@link android.graphics.PixelFormat}.
+         * @hide
          */
         public Builder setFormat(@PixelFormat.Format int format) {
             mFormat = format;
@@ -454,6 +478,7 @@
          * not be displayed.
          *
          * @param protectedContent Whether to require a protected sink.
+         * @hide
          */
         public Builder setProtected(boolean protectedContent) {
             if (protectedContent) {
@@ -469,6 +494,7 @@
          * will prevent the surfaces content from being copied by another process. In
          * particular screenshots and VNC servers will be disabled. This is however
          * not a complete prevention of readback as {@link #setProtected}.
+         * @hide
          */
         public Builder setSecure(boolean secure) {
             if (secure) {
@@ -501,6 +527,7 @@
          * If the underlying buffer lacks an alpha channel, it is as if setOpaque(true)
          * were set automatically.
          * @param opaque Whether the Surface is OPAQUE.
+         * @hide
          */
         public Builder setOpaque(boolean opaque) {
             if (opaque) {
@@ -519,6 +546,7 @@
          * of the parent.
          *
          * @param parent The parent control.
+         * @hide
          */
         public Builder setParent(SurfaceControl parent) {
             mParent = parent;
@@ -534,6 +562,7 @@
          *
          * @param windowType A window-type
          * @param ownerUid UID of the window owner.
+         * @hide
          */
         public Builder setMetadata(int windowType, int ownerUid) {
             if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
@@ -552,6 +581,7 @@
          * solid color (that is, solid before plane alpha). Currently that color is black.
          *
          * @param isColorLayer Whether to create a color layer.
+         * @hide
          */
         public Builder setColorLayer(boolean isColorLayer) {
             if (isColorLayer) {
@@ -573,6 +603,7 @@
          * as a parent of renderable layers.
          *
          * @param isContainerLayer Whether to create a container layer.
+         * @hide
          */
         public Builder setContainerLayer(boolean isContainerLayer) {
             if (isContainerLayer) {
@@ -592,6 +623,7 @@
          *
          * TODO: Finish conversion to individual builder methods?
          * @param flags The combined flags
+         * @hide
          */
         public Builder setFlags(int flags) {
             mFlags = flags;
@@ -660,9 +692,11 @@
         mCloseGuard.open("release");
     }
 
-    // This is a transfer constructor, useful for transferring a live SurfaceControl native
-    // object to another Java wrapper which could have some different behavior, e.g.
-    // event logging.
+    /** This is a transfer constructor, useful for transferring a live SurfaceControl native
+     * object to another Java wrapper which could have some different behavior, e.g.
+     * event logging.
+     * @hide
+     */
     public SurfaceControl(SurfaceControl other) {
         mName = other.mName;
         mWidth = other.mWidth;
@@ -678,10 +712,16 @@
         mCloseGuard.open("release");
     }
 
+    /**
+     * @hide
+     */
     public SurfaceControl() {
         mCloseGuard.open("release");
     }
 
+    /**
+     * @hide
+     */
     public void readFromParcel(Parcel in) {
         if (in == null) {
             throw new IllegalArgumentException("source must not be null");
@@ -698,11 +738,17 @@
         assignNativeObject(object);
     }
 
+    /**
+     * @hide
+     */
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /**
+     * @hide
+     */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mName);
@@ -735,6 +781,9 @@
         proto.end(token);
     }
 
+    /**
+     * @hide
+     */
     public static final Creator<SurfaceControl> CREATOR
             = new Creator<SurfaceControl>() {
         public SurfaceControl createFromParcel(Parcel in) {
@@ -746,6 +795,9 @@
         }
     };
 
+    /**
+     * @hide
+     */
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -764,6 +816,7 @@
      * Release the local reference to the server-side surface.
      * Always call release() when you're done with a Surface.
      * This will make the surface invalid.
+     * @hide
      */
     public void release() {
         if (mNativeObject != 0) {
@@ -777,6 +830,7 @@
      * Free all server-side state associated with this surface and
      * release this object's reference.  This method can only be
      * called from the process that created the service.
+     * @hide
      */
     public void destroy() {
         if (mNativeObject != 0) {
@@ -788,6 +842,7 @@
 
     /**
      * Disconnect any client still connected to the surface.
+     * @hide
      */
     public void disconnect() {
         if (mNativeObject != 0) {
@@ -800,6 +855,9 @@
                 "mNativeObject is null. Have you called release() already?");
     }
 
+    /**
+     * @hide
+     */
     public boolean isValid() {
         return mNativeObject != 0;
     }
@@ -809,7 +867,9 @@
      * needs to be inside open/closeTransaction block
      */
 
-    /** start a transaction */
+    /** start a transaction
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void openTransaction() {
         synchronized (SurfaceControl.class) {
@@ -838,6 +898,7 @@
      * This clears the supplied transaction in an identical fashion to {@link Transaction#merge}.
      * <p>
      * This is a utility for interop with legacy-code and will go away with the Global Transaction.
+     * @hide
      */
     @Deprecated
     public static void mergeToGlobalTransaction(Transaction t) {
@@ -846,46 +907,69 @@
         }
     }
 
-    /** end a transaction */
+    /** end a transaction 
+     * @hide 
+     */
     @UnsupportedAppUsage
     public static void closeTransaction() {
         closeTransaction(false);
     }
 
+    /**
+     * @hide
+     */
     public static void closeTransactionSync() {
         closeTransaction(true);
     }
 
+    /**
+     * @hide
+     */
     public void deferTransactionUntil(IBinder handle, long frame) {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.deferTransactionUntil(this, handle, frame);
         }
     }
 
+    /**
+     * @hide
+     */
     public void deferTransactionUntil(Surface barrier, long frame) {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame);
         }
     }
 
+    /**
+     * @hide
+     */
     public void reparentChildren(IBinder newParentHandle) {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.reparentChildren(this, newParentHandle);
         }
     }
 
+    /**
+     * @hide
+     */
     public void reparent(IBinder newParentHandle) {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.reparent(this, newParentHandle);
         }
     }
 
+    /**
+     * @hide
+     */
     public void detachChildren() {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.detachChildren(this);
         }
     }
 
+    /**
+     * @hide
+     */
     public void setOverrideScalingMode(int scalingMode) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -893,16 +977,25 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public IBinder getHandle() {
         return nativeGetHandle(mNativeObject);
     }
 
+    /**
+     * @hide
+     */
     public static void setAnimationTransaction() {
         synchronized (SurfaceControl.class) {
             sGlobalTransaction.setAnimationTransaction();
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void setLayer(int zorder) {
         checkNotReleased();
@@ -911,6 +1004,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setRelativeLayer(SurfaceControl relativeTo, int zorder) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -918,6 +1014,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void setPosition(float x, float y) {
         checkNotReleased();
@@ -926,6 +1025,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setGeometryAppliesWithResize() {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -933,6 +1035,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setBufferSize(int w, int h) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -940,6 +1045,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void hide() {
         checkNotReleased();
@@ -948,6 +1056,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void show() {
         checkNotReleased();
@@ -956,6 +1067,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setTransparentRegionHint(Region region) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -963,24 +1077,39 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public boolean clearContentFrameStats() {
         checkNotReleased();
         return nativeClearContentFrameStats(mNativeObject);
     }
 
+    /**
+     * @hide
+     */
     public boolean getContentFrameStats(WindowContentFrameStats outStats) {
         checkNotReleased();
         return nativeGetContentFrameStats(mNativeObject, outStats);
     }
 
+    /**
+     * @hide
+     */
     public static boolean clearAnimationFrameStats() {
         return nativeClearAnimationFrameStats();
     }
 
+    /**
+     * @hide
+     */
     public static boolean getAnimationFrameStats(WindowAnimationFrameStats outStats) {
         return nativeGetAnimationFrameStats(outStats);
     }
 
+    /**
+     * @hide
+     */
     public void setAlpha(float alpha) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -988,6 +1117,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setColor(@Size(3) float[] color) {
         checkNotReleased();
         synchronized (SurfaceControl.class) {
@@ -995,6 +1127,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -1007,6 +1142,7 @@
      *
      * @param matrix The matrix to apply.
      * @param float9 An array of 9 floats to be used to extract the values from the matrix.
+     * @hide
      */
     public void setMatrix(Matrix matrix, float[] float9) {
         checkNotReleased();
@@ -1022,6 +1158,7 @@
      * Sets the color transform for the Surface.
      * @param matrix A float array with 9 values represents a 3x3 transform matrix
      * @param translation A float array with 3 values represents a translation vector
+     * @hide
      */
     public void setColorTransform(@Size(9) float[] matrix, @Size(3) float[] translation) {
         checkNotReleased();
@@ -1037,6 +1174,7 @@
      * constrained by the size of its parent bounds.
      *
      * @param crop Bounds of the crop to apply.
+     * @hide
      */
     public void setWindowCrop(Rect crop) {
         checkNotReleased();
@@ -1050,6 +1188,7 @@
      *
      * @param width width of crop rect
      * @param height height of crop rect
+     * @hide
      */
     public void setWindowCrop(int width, int height) {
         checkNotReleased();
@@ -1062,6 +1201,7 @@
      * Sets the corner radius of a {@link SurfaceControl}.
      *
      * @param cornerRadius Corner radius in pixels.
+     * @hide
      */
     public void setCornerRadius(float cornerRadius) {
         checkNotReleased();
@@ -1070,6 +1210,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setLayerStack(int layerStack) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -1077,6 +1220,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setOpaque(boolean isOpaque) {
         checkNotReleased();
 
@@ -1085,6 +1231,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setSecure(boolean isSecure) {
         checkNotReleased();
 
@@ -1093,18 +1242,27 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public int getWidth() {
         synchronized (mSizeLock) {
             return mWidth;
         }
     }
 
+    /**
+     * @hide
+     */
     public int getHeight() {
         synchronized (mSizeLock) {
             return mHeight;
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
     public String toString() {
         return "Surface(name=" + mName + ")/@0x" +
@@ -1120,38 +1278,85 @@
      * Describes the properties of a physical display known to surface flinger.
      */
     public static final class PhysicalDisplayInfo {
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public int width;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public int height;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float refreshRate;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float density;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float xDpi;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float yDpi;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public boolean secure;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public long appVsyncOffsetNanos;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public long presentationDeadlineNanos;
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public PhysicalDisplayInfo() {
         }
 
+        /**
+         * @hide
+         */
         public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
             copyFrom(other);
         }
 
+        /**
+         * @hide
+         */
         @Override
         public boolean equals(Object o) {
             return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
         }
 
+        /**
+         * @hide
+         */
         public boolean equals(PhysicalDisplayInfo other) {
             return other != null
                     && width == other.width
@@ -1165,11 +1370,17 @@
                     && presentationDeadlineNanos == other.presentationDeadlineNanos;
         }
 
+        /**
+         * @hide
+         */
         @Override
         public int hashCode() {
             return 0; // don't care
         }
 
+        /**
+         * @hide
+         */
         public void copyFrom(PhysicalDisplayInfo other) {
             width = other.width;
             height = other.height;
@@ -1182,7 +1393,9 @@
             presentationDeadlineNanos = other.presentationDeadlineNanos;
         }
 
-        // For debugging purposes
+        /**
+         * @hide
+         */
         @Override
         public String toString() {
             return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
@@ -1192,6 +1405,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public static void setDisplayPowerMode(IBinder displayToken, int mode) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1199,6 +1415,9 @@
         nativeSetDisplayPowerMode(displayToken, mode);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
         if (displayToken == null) {
@@ -1207,6 +1426,9 @@
         return nativeGetDisplayConfigs(displayToken);
     }
 
+    /**
+     * @hide
+     */
     public static int getActiveConfig(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1253,6 +1475,9 @@
     }
 
 
+    /**
+     * @hide
+     */
     public static boolean setActiveConfig(IBinder displayToken, int id) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1260,6 +1485,9 @@
         return nativeSetActiveConfig(displayToken, id);
     }
 
+    /**
+     * @hide
+     */
     public static int[] getDisplayColorModes(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1267,6 +1495,9 @@
         return nativeGetDisplayColorModes(displayToken);
     }
 
+    /**
+     * @hide
+     */
     public static int getActiveColorMode(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1274,6 +1505,9 @@
         return nativeGetActiveColorMode(displayToken);
     }
 
+    /**
+     * @hide
+     */
     public static boolean setActiveColorMode(IBinder displayToken, int colorMode) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1281,6 +1515,9 @@
         return nativeSetActiveColorMode(displayToken, colorMode);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void setDisplayProjection(IBinder displayToken,
             int orientation, Rect layerStackRect, Rect displayRect) {
@@ -1290,6 +1527,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
         synchronized (SurfaceControl.class) {
@@ -1297,6 +1537,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void setDisplaySurface(IBinder displayToken, Surface surface) {
         synchronized (SurfaceControl.class) {
@@ -1304,12 +1547,18 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public static void setDisplaySize(IBinder displayToken, int width, int height) {
         synchronized (SurfaceControl.class) {
             sGlobalTransaction.setDisplaySize(displayToken, width, height);
         }
     }
 
+    /**
+     * @hide
+     */
     public static Display.HdrCapabilities getHdrCapabilities(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1317,6 +1566,9 @@
         return nativeGetHdrCapabilities(displayToken);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static IBinder createDisplay(String name, boolean secure) {
         if (name == null) {
@@ -1325,6 +1577,9 @@
         return nativeCreateDisplay(name, secure);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void destroyDisplay(IBinder displayToken) {
         if (displayToken == null) {
@@ -1333,6 +1588,9 @@
         nativeDestroyDisplay(displayToken);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static IBinder getBuiltInDisplay(int builtInDisplayId) {
         return nativeGetBuiltInDisplay(builtInDisplayId);
@@ -1340,6 +1598,7 @@
 
     /**
      * @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int)
+     * @hide
      */
     public static void screenshot(IBinder display, Surface consumer) {
         screenshot(display, consumer, new Rect(), 0, 0, false, 0);
@@ -1350,6 +1609,7 @@
      *
      * @param consumer The {@link Surface} to take the screenshot into.
      * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)
+     * @hide
      */
     public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width,
             int height, boolean useIdentityTransform, int rotation) {
@@ -1368,6 +1628,7 @@
 
     /**
      * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
+     * @hide
      */
     @UnsupportedAppUsage
     public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
@@ -1385,6 +1646,7 @@
      * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
      *
      * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
+     * @hide
      */
     @UnsupportedAppUsage
     public static Bitmap screenshot(Rect sourceCrop, int width, int height,
@@ -1428,6 +1690,7 @@
      *                             this is useful for returning screenshots that are independent of
      *                             device orientation.
      * @return Returns a GraphicBuffer that contains the captured content.
+     * @hide
      */
     public static GraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, int width,
             int height, boolean useIdentityTransform, int rotation) {
@@ -1459,12 +1722,16 @@
      *                         screen will be scaled up/down.
      *
      * @return Returns a GraphicBuffer that contains the layer capture.
+     * @hide
      */
     public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
             float frameScale) {
         return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale);
     }
 
+    /**
+     * @hide
+     */
     public static class Transaction implements Closeable {
         public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
                 Transaction.class.getClassLoader(),
@@ -1474,6 +1741,9 @@
         private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
         Runnable mFreeNativeResources;
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction() {
             mNativeObject = nativeCreateTransaction();
@@ -1484,6 +1754,7 @@
         /**
          * Apply the transaction, clearing it's state, and making it usable
          * as a new transaction.
+         * @hide
          */
         @UnsupportedAppUsage
         public void apply() {
@@ -1493,6 +1764,7 @@
         /**
          * Close the transaction, if the transaction was not already applied this will cancel the
          * transaction.
+         * @hide
          */
         @Override
         public void close() {
@@ -1502,6 +1774,7 @@
 
         /**
          * Jankier version of apply. Avoid use (b/28068298).
+         * @hide
          */
         public void apply(boolean sync) {
             applyResizedSurfaces();
@@ -1520,6 +1793,9 @@
             mResizedSurfaces.clear();
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction show(SurfaceControl sc) {
             sc.checkNotReleased();
@@ -1527,6 +1803,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction hide(SurfaceControl sc) {
             sc.checkNotReleased();
@@ -1534,6 +1813,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setPosition(SurfaceControl sc, float x, float y) {
             sc.checkNotReleased();
@@ -1541,6 +1823,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setBufferSize(SurfaceControl sc, int w, int h) {
             sc.checkNotReleased();
@@ -1549,6 +1834,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setLayer(SurfaceControl sc, int z) {
             sc.checkNotReleased();
@@ -1556,6 +1844,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
             sc.checkNotReleased();
             nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
@@ -1563,6 +1854,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
             sc.checkNotReleased();
             nativeSetTransparentRegionHint(mNativeObject,
@@ -1570,6 +1864,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setAlpha(SurfaceControl sc, float alpha) {
             sc.checkNotReleased();
@@ -1577,6 +1874,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
             sc.checkNotReleased();
             nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
@@ -1592,12 +1892,16 @@
          * @param fromToken The token of a window that currently has touch focus.
          * @param toToken The token of the window that should receive touch focus in
          * place of the first.
+         * @hide
          */
         public Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) {
             nativeTransferTouchFocus(mNativeObject, fromToken, toToken);
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setMatrix(SurfaceControl sc,
                 float dsdx, float dtdx, float dtdy, float dsdy) {
@@ -1607,6 +1911,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setMatrix(SurfaceControl sc, Matrix matrix, float[] float9) {
             matrix.getValues(float9);
@@ -1620,6 +1927,7 @@
          * Sets the color transform for the Surface.
          * @param matrix A float array with 9 values represents a 3x3 transform matrix
          * @param translation A float array with 3 values represents a translation vector
+         * @hide
          */
         public Transaction setColorTransform(SurfaceControl sc, @Size(9) float[] matrix,
                 @Size(3) float[] translation) {
@@ -1628,6 +1936,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
             sc.checkNotReleased();
@@ -1641,6 +1952,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
             sc.checkNotReleased();
             nativeSetWindowCrop(mNativeObject, sc.mNativeObject, 0, 0, width, height);
@@ -1652,6 +1966,7 @@
          * @param sc SurfaceControl
          * @param cornerRadius Corner radius in pixels.
          * @return Itself.
+         * @hide
          */
         @UnsupportedAppUsage
         public Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
@@ -1662,6 +1977,9 @@
         }
 
         @UnsupportedAppUsage
+        /**
+         * @hide
+         */
         public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
             sc.checkNotReleased();
             nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
@@ -1669,6 +1987,9 @@
         }
 
         @UnsupportedAppUsage
+        /**
+         * @hide
+         */
         public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
                 long frameNumber) {
             if (frameNumber < 0) {
@@ -1680,6 +2001,9 @@
         }
 
         @UnsupportedAppUsage
+        /**
+         * @hide
+         */
         public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
                 long frameNumber) {
             if (frameNumber < 0) {
@@ -1691,13 +2015,18 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
             sc.checkNotReleased();
             nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
             return this;
         }
 
-        /** Re-parents a specific child layer to a new parent */
+        /** Re-parents a specific child layer to a new parent 
+         * @hide
+         */
         public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
             sc.checkNotReleased();
             nativeReparent(mNativeObject, sc.mNativeObject,
@@ -1705,12 +2034,18 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction detachChildren(SurfaceControl sc) {
             sc.checkNotReleased();
             nativeSeverChildren(mNativeObject, sc.mNativeObject);
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
             sc.checkNotReleased();
             nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
@@ -1721,6 +2056,7 @@
         /**
          * Sets a color for the Surface.
          * @param color A float array with three values to represent r, g, b in range [0..1]
+         * @hide
          */
         @UnsupportedAppUsage
         public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
@@ -1735,6 +2071,7 @@
          * arrives. As transform matrix and size are already frozen in this fashion,
          * this enables totally freezing the surface until the resize has completed
          * (at which point the geometry influencing aspects of this transaction will then occur)
+         * @hide
          */
         public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
             sc.checkNotReleased();
@@ -1745,6 +2082,7 @@
         /**
          * Sets the security of the surface.  Setting the flag is equivalent to creating the
          * Surface with the {@link #SECURE} flag.
+         * @hide
          */
         public Transaction setSecure(SurfaceControl sc, boolean isSecure) {
             sc.checkNotReleased();
@@ -1759,6 +2097,7 @@
         /**
          * Sets the opacity of the surface.  Setting the flag is equivalent to creating the
          * Surface with the {@link #OPAQUE} flag.
+         * @hide
          */
         public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
             sc.checkNotReleased();
@@ -1770,6 +2109,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
             if (displayToken == null) {
                 throw new IllegalArgumentException("displayToken must not be null");
@@ -1785,6 +2127,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setDisplayLayerStack(IBinder displayToken, int layerStack) {
             if (displayToken == null) {
                 throw new IllegalArgumentException("displayToken must not be null");
@@ -1793,6 +2138,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setDisplayProjection(IBinder displayToken,
                 int orientation, Rect layerStackRect, Rect displayRect) {
             if (displayToken == null) {
@@ -1810,6 +2158,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setDisplaySize(IBinder displayToken, int width, int height) {
             if (displayToken == null) {
                 throw new IllegalArgumentException("displayToken must not be null");
@@ -1822,7 +2173,9 @@
             return this;
         }
 
-        /** flag the transaction as an animation */
+        /** flag the transaction as an animation 
+         * @hide
+         */
         public Transaction setAnimationTransaction() {
             nativeSetAnimationTransaction(mNativeObject);
             return this;
@@ -1835,6 +2188,7 @@
          * order not to miss frame deadlines.
          * <p>
          * Corresponds to setting ISurfaceComposer::eEarlyWakeup
+         * @hide
          */
         public Transaction setEarlyWakeup() {
             nativeSetEarlyWakeup(mNativeObject);
@@ -1844,6 +2198,7 @@
         /**
          * Merge the other transaction into this transaction, clearing the
          * other transaction as if it had been applied.
+         * @hide
          */
         public Transaction merge(Transaction other) {
             mResizedSurfaces.putAll(other.mResizedSurfaces);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4ff73cf..abefd55 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8202,6 +8202,19 @@
      * <p>The populated structure is then passed to the service through
      * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}.
      *
+     * <p><b>Note: </b>views that manage a virtual structure under this view must populate just
+     * the node representing this view and return right away, then asynchronously report (not
+     * necessarily in the UI thread) when the children nodes appear, disappear or have their text
+     * changed by calling
+     * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)},
+     * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and
+     * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence, int)}
+     * respectively. The structure for the a child must be created using
+     * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, int)}, and the
+     * {@code autofillId} for a child can be obtained either through
+     * {@code childStructure.getAutofillId()} or
+     * {@link ContentCaptureSession#newAutofillId(AutofillId, int)}.
+     *
      * <p><b>Note: </b>the following methods of the {@code structure} will be ignored:
      * <ul>
      *   <li>{@link ViewStructure#setChildCount(int)}
@@ -8238,10 +8251,6 @@
         } else {
             structure.setId(id, null, null, null);
         }
-        if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
-            //TODO(b/111276913): STOPSHIP - don't set it if not needed
-            structure.setDataIsSensitive(false);
-        }
 
         if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
                 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d7c8aed..793c315 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -43,6 +43,7 @@
 import android.text.style.URLSpan;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.LongArray;
 import android.util.Pools.SynchronizedPool;
 import android.view.TouchDelegate;
@@ -91,6 +92,8 @@
 
     private static final boolean DEBUG = false;
 
+    private static final String TAG = "AccessibilityNodeInfo";
+
     /** @hide */
     public static final int UNDEFINED_CONNECTION_ID = -1;
 
@@ -990,6 +993,7 @@
      * <strong>Note:</strong> Cannot be called from an
      * {@link android.accessibilityservice.AccessibilityService}.
      * This class is made immutable before being delivered to an AccessibilityService.
+     * Note that a view cannot be made its own child.
      * </p>
      *
      * @param child The child.
@@ -1037,6 +1041,7 @@
      * hierarchy for accessibility purposes. This enables custom views that draw complex
      * content to report them selves as a tree of virtual views, thus conveying their
      * logical structure.
+     * Note that a view cannot be made its own child.
      * </p>
      *
      * @param root The root of the virtual subtree.
@@ -1054,6 +1059,11 @@
         final int rootAccessibilityViewId =
             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+        if (childNodeId == mSourceNodeId) {
+            Log.e(TAG, "Rejecting attempt to make a View its own child");
+            return;
+        }
+
         // If we're checking uniqueness and the ID already exists, abort.
         if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
             return;
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 95a346f..c630177 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -794,7 +794,7 @@
      * @deprecated All window animations are running with detached wallpaper.
      */
     public boolean getDetachWallpaper() {
-        return false;
+        return true;
     }
 
     /**
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index e962e7c..ff45efd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -15,6 +15,8 @@
  */
 package android.view.contentcapture;
 
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
@@ -24,9 +26,12 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
 
 import java.io.PrintWriter;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -48,6 +53,11 @@
 
     private static final String BG_THREAD_NAME = "intel_svc_streamer_thread";
 
+    /**
+     * Timeout for calls to system_server.
+     */
+    private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
+
     // TODO(b/121044306): define a way to dynamically set them(for example, using settings?)
     static final boolean VERBOSE = false;
     static final boolean DEBUG = true; // STOPSHIP if not set to false
@@ -116,8 +126,8 @@
 
     /** @hide */
     public void onActivityStarted(@NonNull IBinder applicationToken,
-            @NonNull ComponentName activityComponent) {
-        getMainContentCaptureSession().start(applicationToken, activityComponent);
+            @NonNull ComponentName activityComponent, int flags) {
+        getMainContentCaptureSession().start(applicationToken, activityComponent, flags);
     }
 
     /** @hide */
@@ -142,8 +152,21 @@
      */
     @Nullable
     public ComponentName getServiceComponentName() {
-        //TODO(b/121047489): implement
-        return null;
+        if (!isContentCaptureEnabled()) {
+            return null;
+        }
+        // Wait for system server to return the component name.
+        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+        mHandler.sendMessage(obtainMessage(
+                ContentCaptureManager::handleReceiverServiceComponentName,
+                this, mContext.getUserId(), resultReceiver));
+
+        try {
+            return resultReceiver.getParcelableResult();
+        } catch (RemoteException e) {
+            // Unable to retrieve component name in a reasonable amount of time.
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -191,4 +214,14 @@
             pw.print(prefix); pw.println("No sessions");
         }
     }
+
+
+    /** Retrieves the component name of the target content capture service through system_server. */
+    private void handleReceiverServiceComponentName(int userId, IResultReceiver resultReceiver) {
+        try {
+            mService.getReceiverServiceComponentName(userId, resultReceiver);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Unable to retrieve service component name: " + e);
+        }
+    }
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 344b9973..6890beaf 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -46,8 +46,7 @@
 
     /**
      * Used on {@link #notifyViewTextChanged(AutofillId, CharSequence, int)} to indicate that the
-     *
-     * thext change was caused by user input (for example, through IME).
+     * text change was caused by user input (for example, through IME).
      */
     public static final int FLAG_USER_INPUT = 0x1;
 
@@ -86,6 +85,13 @@
      */
     public static final int STATE_DISABLED_DUPLICATED_ID = 4;
 
+    /**
+     * Session is disabled by FLAG_SECURE
+     *
+     * @hide
+     */
+    public static final int STATE_DISABLED_BY_FLAG_SECURE = 5;
+
     private static final int INITIAL_CHILDREN_CAPACITY = 5;
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -178,7 +184,7 @@
 
             mCloseGuard.close();
 
-            //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
+            // TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
             // id) and send it to the cache of batched commands
             if (VERBOSE) {
                 Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
@@ -295,6 +301,26 @@
     }
 
     /**
+     * Creates a new {@link AutofillId} for a virtual child, so it can be used to uniquely identify
+     * the children in the session.
+     *
+     * @param parentId id of the virtual view parent (it can be obtained by calling
+     * {@link ViewStructure#getAutofillId()} on the parent).
+     * @param virtualChildId id of the virtual child, relative to the parent.
+     *
+     * @return if for the virtual child
+     *
+     * @throws IllegalArgumentException if the {@code parentId} is a virtual child id.
+     */
+    public @NonNull AutofillId newAutofillId(@NonNull AutofillId parentId, int virtualChildId) {
+        Preconditions.checkNotNull(parentId);
+        Preconditions.checkArgument(!parentId.isVirtual(), "virtual ids cannot have children");
+        // TODO(b/121197119): we need to add the session id to the AutofillId to make them unique
+        // per session
+        return new AutofillId(parentId, virtualChildId);
+    }
+
+    /**
      * Creates a {@link ViewStructure} for a "virtual" view, so it can be passed to
      * {@link #notifyViewAppeared(ViewStructure)} by the view managing the virtual view hierarchy.
      *
@@ -303,12 +329,11 @@
      * @param virtualId id of the virtual child, relative to the parent.
      *
      * @return a new {@link ViewStructure} that can be used for Content Capture purposes.
-     *
-     * @hide
      */
     @NonNull
     public final ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId,
             int virtualId) {
+        // TODO(b/121197119): use the constructor that takes a session id / assert on unit test.
         return new ViewNode.ViewStructureImpl(parentId, virtualId);
     }
 
@@ -356,6 +381,8 @@
                 return "DISABLED_NO_SERVICE";
             case STATE_DISABLED_DUPLICATED_ID:
                 return "DISABLED_DUPLICATED_ID";
+            case STATE_DISABLED_BY_FLAG_SECURE:
+                return "DISABLED_FLAG_SECURE";
             default:
                 return "INVALID:" + state;
         }
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 01776f8..be9c00f 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -32,7 +32,28 @@
   * @hide
   */
 oneway interface IContentCaptureManager {
+    /**
+     * Starts a new session for the provided {@code userId} running as part of the
+     * app's activity identified by {@code activityToken}/{@code componentName}.
+     *
+     * @param sessionId Unique session id as provided by the app.
+     * @param flags Meta flags that enable or disable content capture (see
+     *     {@link IContentCaptureContext#flags}).
+     */
     void startSession(int userId, IBinder activityToken, in ComponentName componentName,
                       String sessionId, int flags, in IResultReceiver result);
+
+    /**
+     * Marks the end of a session for the provided {@code userId} identified by
+     * the corresponding {@code startSession}'s {@code sessionId}.
+     */
     void finishSession(int userId, String sessionId);
+
+    /**
+     * Returns the content capture service's component name (if enabled and
+     * connected).
+     * @param Receiver of the content capture service's @{code ComponentName}
+     *     provided {@code Bundle} with key "{@code EXTRA}".
+     */
+    void getReceiverServiceComponentName(int userId, in IResultReceiver result);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 8be887b..a29aaf0 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -157,7 +157,8 @@
      *
      * @hide
      */
-    void start(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent) {
+    void start(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent,
+            int flags) {
         if (!isContentCaptureEnabled()) return;
 
         if (VERBOSE) {
@@ -166,7 +167,7 @@
         }
 
         mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleStartSession, this,
-                applicationToken, activityComponent));
+                applicationToken, activityComponent, flags));
     }
 
     @Override
@@ -181,7 +182,8 @@
                 obtainMessage(MainContentCaptureSession::handleDestroySession, this));
     }
 
-    private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName) {
+    private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName,
+            int flags) {
         if (mState != STATE_UNKNOWN) {
             // TODO(b/111276913): revisit this scenario
             Log.w(TAG, "ignoring handleStartSession(" + token + ") while on state "
@@ -196,7 +198,6 @@
             Log.v(TAG, "handleStartSession(): token=" + token + ", act="
                     + getActivityDebugName() + ", id=" + mId);
         }
-        final int flags = 0; // TODO(b/111276913): get proper flags
 
         try {
             if (mSystemServerInterface == null) return;
@@ -245,7 +246,11 @@
                 Log.w(TAG, "Failed to link to death on " + binder + ": " + e);
             }
         }
-        if (resultCode == STATE_DISABLED_NO_SERVICE || resultCode == STATE_DISABLED_DUPLICATED_ID) {
+
+        // TODO(b/111276913): change the resultCode to use flags so there's just one flag for
+        // disabled stuff
+        if (resultCode == STATE_DISABLED_NO_SERVICE || resultCode == STATE_DISABLED_DUPLICATED_ID
+                || resultCode == STATE_DISABLED_BY_FLAG_SECURE) {
             mDisabled.set(true);
             handleResetSession(/* resetState= */ false);
         } else {
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index 86b89adb..b7a486a 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
@@ -32,30 +33,188 @@
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
-//TODO(b/111276913): add javadocs / implement Parcelable / implement
-//TODO(b/111276913): for now it's extending ViewNode directly as it needs most of its properties,
+//TODO(b/122484602): add javadocs / implement Parcelable / implement
+//TODO(b/122484602): for now it's extending ViewNode directly as it needs most of its properties,
 // but it might be better to create a common, abstract android.view.ViewNode class that both extend
 // instead
 /** @hide */
 @SystemApi
 public final class ViewNode extends AssistStructure.ViewNode {
 
-    private static final String TAG = "ViewNode";
+    private static final String TAG = ViewNode.class.getSimpleName();
+    private static final boolean VERBOSE = false;
+
+    private static final long FLAGS_HAS_TEXT = 1L << 0;
+    private static final long FLAGS_HAS_COMPLEX_TEXT = 1L << 1;
+    private static final long FLAGS_VISIBILITY_MASK = View.VISIBLE | View.INVISIBLE | View.GONE;
+    private static final long FLAGS_HAS_CLASSNAME = 1L << 4;
+    private static final long FLAGS_HAS_AUTOFILL_ID = 1L << 5;
+    private static final long FLAGS_HAS_AUTOFILL_PARENT_ID = 1L << 6;
+    private static final long FLAGS_HAS_ID = 1L << 7;
+    private static final long FLAGS_HAS_LARGE_COORDS = 1L << 8;
+    private static final long FLAGS_HAS_SCROLL = 1L << 9;
+    private static final long FLAGS_ASSIST_BLOCKED = 1L << 10;
+    private static final long FLAGS_DISABLED = 1L << 11;
+    private static final long FLAGS_CLICKABLE = 1L << 12;
+    private static final long FLAGS_LONG_CLICKABLE = 1L << 13;
+    private static final long FLAGS_CONTEXT_CLICKABLE = 1L << 14;
+    private static final long FLAGS_FOCUSABLE = 1L << 15;
+    private static final long FLAGS_FOCUSED = 1L << 16;
+    private static final long FLAGS_ACCESSIBILITY_FOCUSED = 1L << 17;
+    private static final long FLAGS_CHECKABLE = 1L << 18;
+    private static final long FLAGS_CHECKED = 1L << 19;
+    private static final long FLAGS_SELECTED = 1L << 20;
+    private static final long FLAGS_ACTIVATED = 1L << 21;
+    private static final long FLAGS_OPAQUE = 1L << 22;
+    private static final long FLAGS_HAS_MATRIX = 1L << 23;
+    private static final long FLAGS_HAS_ELEVATION = 1L << 24;
+    private static final long FLAGS_HAS_ALPHA = 1L << 25;
+    private static final long FLAGS_HAS_CONTENT_DESCRIPTION = 1L << 26;
+    private static final long FLAGS_HAS_EXTRAS = 1L << 27;
+    private static final long FLAGS_HAS_LOCALE_LIST = 1L << 28;
+    private static final long FLAGS_HAS_INPUT_TYPE = 1L << 29;
+    private static final long FLAGS_HAS_MIN_TEXT_EMS = 1L << 30;
+    private static final long FLAGS_HAS_MAX_TEXT_EMS = 1L << 31;
+    private static final long FLAGS_HAS_MAX_TEXT_LENGTH = 1L << 32;
+    private static final long FLAGS_HAS_TEXT_ID_ENTRY = 1L << 33;
+    private static final long FLAGS_HAS_AUTOFILL_TYPE = 1L << 34;
+    private static final long FLAGS_HAS_AUTOFILL_VALUE = 1L << 35;
+    private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 36;
+    private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 37;
+
+    /** Flags used to optimize what's written to the parcel */
+    private long mFlags;
 
     private AutofillId mParentAutofillId;
 
-    // TODO(b/111276913): temporarily setting some fields here while they're not accessible from the
-    // superclass
     private AutofillId mAutofillId;
-    private CharSequence mText;
+    private ViewNodeText mText;
     private String mClassName;
+    private int mId = View.NO_ID;
+    private String mIdPackage;
+    private String mIdType;
+    private String mIdEntry;
+    private int mX;
+    private int mY;
+    private int mScrollX;
+    private int mScrollY;
+    private int mWidth;
+    private int mHeight;
+    private Matrix mMatrix;
+    private float mElevation;
+    private float mAlpha = 1.0f;
+    private CharSequence mContentDescription;
+    private Bundle mExtras;
+    private LocaleList mLocaleList;
+    private int mInputType;
+    private int mMinEms = -1;
+    private int mMaxEms = -1;
+    private int mMaxLength = -1;
+    private String mTextIdEntry;
+    private @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
+    private String[] mAutofillHints;
+    private AutofillValue mAutofillValue;
+    private CharSequence[] mAutofillOptions;
 
     /** @hide */
     public ViewNode() {
     }
 
+    private ViewNode(long nodeFlags, @NonNull Parcel parcel) {
+        mFlags = nodeFlags;
+
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
+            mAutofillId = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) {
+            mParentAutofillId = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT) != 0) {
+            mText = new ViewNodeText(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) {
+            mClassName = parcel.readString();
+        }
+        if ((nodeFlags & FLAGS_HAS_ID) != 0) {
+            mId = parcel.readInt();
+            if (mId != View.NO_ID) {
+                mIdEntry = parcel.readString();
+                if (mIdEntry != null) {
+                    mIdType = parcel.readString();
+                    mIdPackage = parcel.readString();
+                }
+            }
+        }
+        if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) {
+            mX = parcel.readInt();
+            mY = parcel.readInt();
+            mWidth = parcel.readInt();
+            mHeight = parcel.readInt();
+        } else {
+            int val = parcel.readInt();
+            mX = val & 0x7fff;
+            mY = (val >> 16) & 0x7fff;
+            val = parcel.readInt();
+            mWidth = val & 0x7fff;
+            mHeight = (val >> 16) & 0x7fff;
+        }
+        if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) {
+            mScrollX = parcel.readInt();
+            mScrollY = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_MATRIX) != 0) {
+            mMatrix = new Matrix();
+            final float[] tmpMatrix = new float[9];
+            parcel.readFloatArray(tmpMatrix);
+            mMatrix.setValues(tmpMatrix);
+        }
+        if ((nodeFlags & FLAGS_HAS_ELEVATION) != 0) {
+            mElevation = parcel.readFloat();
+        }
+        if ((nodeFlags & FLAGS_HAS_ALPHA) != 0) {
+            mAlpha = parcel.readFloat();
+        }
+        if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
+            mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+        }
+        if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) {
+            mExtras = parcel.readBundle();
+        }
+        if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
+            mLocaleList = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
+            mInputType = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+            mMinEms = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+            mMaxEms = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+            mMaxLength = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+            mTextIdEntry = parcel.readString();
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+            mAutofillType = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+            mAutofillHints = parcel.readStringArray();
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+            mAutofillValue = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+            mAutofillOptions = parcel.readCharSequenceArray();
+        }
+    }
+
     /**
      * Returns the {@link AutofillId} of this view's parent, if the parent is also part of the
      * screen observation tree.
@@ -65,53 +224,446 @@
         return mParentAutofillId;
     }
 
-    // TODO(b/111276913): temporarily overwriting some methods
     @Override
     public AutofillId getAutofillId() {
         return mAutofillId;
     }
+
     @Override
     public CharSequence getText() {
-        return mText;
+        return mText != null ? mText.mText : null;
     }
+
     @Override
     public String getClassName() {
         return mClassName;
     }
 
+    @Override
+    public int getId() {
+        return mId;
+    }
+
+    @Override
+    public String getIdPackage() {
+        return mIdPackage;
+    }
+
+    @Override
+    public String getIdType() {
+        return mIdType;
+    }
+
+    @Override
+    public String getIdEntry() {
+        return mIdEntry;
+    }
+
+    @Override
+    public int getLeft() {
+        return mX;
+    }
+
+    @Override
+    public int getTop() {
+        return mY;
+    }
+
+    @Override
+    public int getScrollX() {
+        return mScrollX;
+    }
+
+    @Override
+    public int getScrollY() {
+        return mScrollY;
+    }
+
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public boolean isAssistBlocked() {
+        return (mFlags & FLAGS_ASSIST_BLOCKED) != 0;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return (mFlags & FLAGS_DISABLED) == 0;
+    }
+
+    @Override
+    public boolean isClickable() {
+        return (mFlags & FLAGS_CLICKABLE) != 0;
+    }
+
+    @Override
+    public boolean isLongClickable() {
+        return (mFlags & FLAGS_LONG_CLICKABLE) != 0;
+    }
+
+    @Override
+    public boolean isContextClickable() {
+        return (mFlags & FLAGS_CONTEXT_CLICKABLE) != 0;
+    }
+
+    @Override
+    public boolean isFocusable() {
+        return (mFlags & FLAGS_FOCUSABLE) != 0;
+    }
+
+    @Override
+    public boolean isFocused() {
+        return (mFlags & FLAGS_FOCUSED) != 0;
+    }
+
+    @Override
+    public boolean isAccessibilityFocused() {
+        return (mFlags & FLAGS_ACCESSIBILITY_FOCUSED) != 0;
+    }
+
+    @Override
+    public boolean isCheckable() {
+        return (mFlags & FLAGS_CHECKABLE) != 0;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return (mFlags & FLAGS_CHECKED) != 0;
+    }
+
+    @Override
+    public boolean isSelected() {
+        return (mFlags & FLAGS_SELECTED) != 0;
+    }
+
+    @Override
+    public boolean isActivated() {
+        return (mFlags & FLAGS_ACTIVATED) != 0;
+    }
+
+    @Override
+    public boolean isOpaque() {
+        return (mFlags & FLAGS_OPAQUE) != 0;
+    }
+
+    @Override
+    public Matrix getTransformation() {
+        return mMatrix;
+    }
+
+    @Override
+    public float getElevation() {
+        return mElevation;
+    }
+
+    @Override
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    @Override
+    public CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+    @Override
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public String getHint() {
+        return mText != null ? mText.mHint : null;
+    }
+
+    @Override
+    public int getTextSelectionStart() {
+        return mText != null ? mText.mTextSelectionStart : -1;
+    }
+
+    @Override
+    public int getTextSelectionEnd() {
+        return mText != null ? mText.mTextSelectionEnd : -1;
+    }
+
+    @Override
+    public int getTextColor() {
+        return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
+    }
+
+    @Override
+    public int getTextBackgroundColor() {
+        return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
+    }
+
+    @Override
+    public float getTextSize() {
+        return mText != null ? mText.mTextSize : 0;
+    }
+
+    @Override
+    public int getTextStyle() {
+        return mText != null ? mText.mTextStyle : 0;
+    }
+
+    @Override
+    public int[] getTextLineCharOffsets() {
+        return mText != null ? mText.mLineCharOffsets : null;
+    }
+
+    @Override
+    public int[] getTextLineBaselines() {
+        return mText != null ? mText.mLineBaselines : null;
+    }
+
+    @Override
+    public int getVisibility() {
+        return (int) (mFlags & FLAGS_VISIBILITY_MASK);
+    }
+
+    @Override
+    public int getInputType() {
+        return mInputType;
+    }
+
+    @Override
+    public int getMinTextEms() {
+        return mMinEms;
+    }
+
+    @Override
+    public int getMaxTextEms() {
+        return mMaxEms;
+    }
+
+    @Override
+    public int getMaxTextLength() {
+        return mMaxLength;
+    }
+
+    @Override
+    public String getTextIdEntry() {
+        return mTextIdEntry;
+    }
+
+    @Override
+    public @View.AutofillType int getAutofillType() {
+        return mAutofillType;
+    }
+
+    @Override
+    @Nullable public String[] getAutofillHints() {
+        return mAutofillHints;
+    }
+
+    @Override
+    @Nullable public AutofillValue getAutofillValue() {
+        return mAutofillValue;
+    }
+
+    @Override
+    @Nullable public CharSequence[] getAutofillOptions() {
+        return mAutofillOptions;
+    }
+
+    @Override
+    public LocaleList getLocaleList() {
+        return mLocaleList;
+    }
+
+    private void writeSelfToParcel(@NonNull Parcel parcel, int parcelFlags) {
+        long nodeFlags = mFlags;
+
+        if (mAutofillId != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_ID;
+        }
+
+        if (mParentAutofillId != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_PARENT_ID;
+        }
+
+        if (mText != null) {
+            nodeFlags |= FLAGS_HAS_TEXT;
+            if (!mText.isSimple()) {
+                nodeFlags |= FLAGS_HAS_COMPLEX_TEXT;
+            }
+        }
+        if (mClassName != null) {
+            nodeFlags |= FLAGS_HAS_CLASSNAME;
+        }
+        if (mId != View.NO_ID) {
+            nodeFlags |= FLAGS_HAS_ID;
+        }
+        if ((mX & ~0x7fff) != 0 || (mY & ~0x7fff) != 0
+                || (mWidth & ~0x7fff) != 0 | (mHeight & ~0x7fff) != 0) {
+            nodeFlags |= FLAGS_HAS_LARGE_COORDS;
+        }
+        if (mScrollX != 0 || mScrollY != 0) {
+            nodeFlags |= FLAGS_HAS_SCROLL;
+        }
+        if (mMatrix != null) {
+            nodeFlags |= FLAGS_HAS_MATRIX;
+        }
+        if (mElevation != 0) {
+            nodeFlags |= FLAGS_HAS_ELEVATION;
+        }
+        if (mAlpha != 1.0f) {
+            nodeFlags |= FLAGS_HAS_ALPHA;
+        }
+        if (mContentDescription != null) {
+            nodeFlags |= FLAGS_HAS_CONTENT_DESCRIPTION;
+        }
+        if (mExtras != null) {
+            nodeFlags |= FLAGS_HAS_EXTRAS;
+        }
+        if (mLocaleList != null) {
+            nodeFlags |= FLAGS_HAS_LOCALE_LIST;
+        }
+        if (mInputType != 0) {
+            nodeFlags |= FLAGS_HAS_INPUT_TYPE;
+        }
+        if (mMinEms > -1) {
+            nodeFlags |= FLAGS_HAS_MIN_TEXT_EMS;
+        }
+        if (mMaxEms > -1) {
+            nodeFlags |= FLAGS_HAS_MAX_TEXT_EMS;
+        }
+        if (mMaxLength > -1) {
+            nodeFlags |= FLAGS_HAS_MAX_TEXT_LENGTH;
+        }
+        if (mTextIdEntry != null) {
+            nodeFlags |= FLAGS_HAS_TEXT_ID_ENTRY;
+        }
+        if (mAutofillValue != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_VALUE;
+        }
+        if (mAutofillType != View.AUTOFILL_TYPE_NONE) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_TYPE;
+        }
+        if (mAutofillHints != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_HINTS;
+        }
+        if (mAutofillOptions != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_OPTIONS;
+        }
+        parcel.writeLong(nodeFlags);
+
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
+            parcel.writeParcelable(mAutofillId, parcelFlags);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) {
+            parcel.writeParcelable(mParentAutofillId, parcelFlags);
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT) != 0) {
+            mText.writeToParcel(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) {
+            parcel.writeString(mClassName);
+        }
+        if ((nodeFlags & FLAGS_HAS_ID) != 0) {
+            parcel.writeInt(mId);
+            if (mId != View.NO_ID) {
+                parcel.writeString(mIdEntry);
+                if (mIdEntry != null) {
+                    parcel.writeString(mIdType);
+                    parcel.writeString(mIdPackage);
+                }
+            }
+        }
+        if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) {
+            parcel.writeInt(mX);
+            parcel.writeInt(mY);
+            parcel.writeInt(mWidth);
+            parcel.writeInt(mHeight);
+        } else {
+            parcel.writeInt((mY << 16) | mX);
+            parcel.writeInt((mHeight << 16) | mWidth);
+        }
+        if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) {
+            parcel.writeInt(mScrollX);
+            parcel.writeInt(mScrollY);
+        }
+        if ((nodeFlags & FLAGS_HAS_MATRIX) != 0) {
+            //TODO(b/122484602): use a singleton tmpMatrix (if logic is not moved to superclass)
+            final float[] tmpMatrix = new float[9];
+            mMatrix.getValues(tmpMatrix);
+            parcel.writeFloatArray(tmpMatrix);
+        }
+        if ((nodeFlags & FLAGS_HAS_ELEVATION) != 0) {
+            parcel.writeFloat(mElevation);
+        }
+        if ((nodeFlags & FLAGS_HAS_ALPHA) != 0) {
+            parcel.writeFloat(mAlpha);
+        }
+        if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
+            TextUtils.writeToParcel(mContentDescription, parcel, 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) {
+            parcel.writeBundle(mExtras);
+        }
+        if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
+            parcel.writeParcelable(mLocaleList, 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
+            parcel.writeInt(mInputType);
+        }
+        if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+            parcel.writeInt(mMinEms);
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+            parcel.writeInt(mMaxEms);
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+            parcel.writeInt(mMaxLength);
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+            parcel.writeString(mTextIdEntry);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+            parcel.writeInt(mAutofillType);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+            parcel.writeStringArray(mAutofillHints);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+            parcel.writeParcelable(mAutofillValue, 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+            parcel.writeCharSequenceArray(mAutofillOptions);
+        }
+    }
+
     /** @hide */
     public static void writeToParcel(@NonNull Parcel parcel, @Nullable ViewNode node, int flags) {
         if (node == null) {
-            parcel.writeParcelable(null, flags);
-            return;
+            parcel.writeLong(0);
+        } else {
+            node.writeSelfToParcel(parcel, flags);
         }
-        parcel.writeParcelable(node.mAutofillId, flags);
-        parcel.writeParcelable(node.mParentAutofillId, flags);
-        parcel.writeCharSequence(node.mText);
-        parcel.writeString(node.mClassName);
     }
 
     /** @hide */
     public static @Nullable ViewNode readFromParcel(@NonNull Parcel parcel) {
-        final AutofillId id = parcel.readParcelable(null);
-        if (id == null) return null;
-
-        final ViewNode node = new ViewNode();
-
-        node.mAutofillId = id;
-        node.mParentAutofillId = parcel.readParcelable(null);
-        node.mText = parcel.readCharSequence();
-        node.mClassName = parcel.readString();
-
-        return node;
+        final long nodeFlags = parcel.readLong();
+        return nodeFlags == 0 ? new ViewNode() : new ViewNode(nodeFlags, parcel);
     }
 
     /** @hide */
-    static final class ViewStructureImpl extends ViewStructure {
+    @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+    public static final class ViewStructureImpl extends ViewStructure {
 
         final ViewNode mNode = new ViewNode();
 
-        ViewStructureImpl(@NonNull View view) {
+        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        public ViewStructureImpl(@NonNull View view) {
             mNode.mAutofillId = Preconditions.checkNotNull(view).getAutofillId();
             final ViewParent parent = view.getParent();
             if (parent instanceof View) {
@@ -119,179 +671,212 @@
             }
         }
 
-        ViewStructureImpl(@NonNull AutofillId parentId, int virtualId) {
+        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        public ViewStructureImpl(@NonNull AutofillId parentId, int virtualId) {
             mNode.mParentAutofillId = Preconditions.checkNotNull(parentId);
             mNode.mAutofillId = new AutofillId(parentId, virtualId);
         }
 
+        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        public ViewNode getNode() {
+            return mNode;
+        }
+
         @Override
         public void setId(int id, String packageName, String typeName, String entryName) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mId = id;
+            mNode.mIdPackage = packageName;
+            mNode.mIdType = typeName;
+            mNode.mIdEntry = entryName;
         }
 
         @Override
         public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mX = left;
+            mNode.mY = top;
+            mNode.mScrollX = scrollX;
+            mNode.mScrollY = scrollY;
+            mNode.mWidth = width;
+            mNode.mHeight = height;
         }
 
         @Override
         public void setTransformation(Matrix matrix) {
-            // TODO(b/111276913): implement or move to superclass
+            if (matrix == null) {
+                mNode.mMatrix = null;
+            } else {
+                mNode.mMatrix = new Matrix(matrix);
+            }
         }
 
         @Override
         public void setElevation(float elevation) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mElevation = elevation;
         }
 
         @Override
         public void setAlpha(float alpha) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mAlpha = alpha;
         }
 
         @Override
         public void setVisibility(int visibility) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_VISIBILITY_MASK)
+                    | (visibility & FLAGS_VISIBILITY_MASK);
         }
 
         @Override
         public void setAssistBlocked(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_ASSIST_BLOCKED)
+                    | (state ? FLAGS_ASSIST_BLOCKED : 0);
         }
 
         @Override
         public void setEnabled(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_DISABLED) | (state ? 0 : FLAGS_DISABLED);
         }
 
         @Override
         public void setClickable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CLICKABLE) | (state ? FLAGS_CLICKABLE : 0);
         }
 
         @Override
         public void setLongClickable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_LONG_CLICKABLE)
+                    | (state ? FLAGS_LONG_CLICKABLE : 0);
         }
 
         @Override
         public void setContextClickable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CONTEXT_CLICKABLE)
+                    | (state ? FLAGS_CONTEXT_CLICKABLE : 0);
         }
 
         @Override
         public void setFocusable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSABLE) | (state ? FLAGS_FOCUSABLE : 0);
         }
 
         @Override
         public void setFocused(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSED) | (state ? FLAGS_FOCUSED : 0);
         }
 
         @Override
         public void setAccessibilityFocused(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_ACCESSIBILITY_FOCUSED)
+                    | (state ? FLAGS_ACCESSIBILITY_FOCUSED : 0);
         }
 
         @Override
         public void setCheckable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKABLE) | (state ? FLAGS_CHECKABLE : 0);
         }
 
         @Override
         public void setChecked(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKED) | (state ? FLAGS_CHECKED : 0);
         }
 
         @Override
         public void setSelected(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_SELECTED) | (state ? FLAGS_SELECTED : 0);
         }
 
         @Override
         public void setActivated(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_ACTIVATED) | (state ? FLAGS_ACTIVATED : 0);
         }
 
         @Override
         public void setOpaque(boolean opaque) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_OPAQUE) | (opaque ? FLAGS_OPAQUE : 0);
         }
 
         @Override
         public void setClassName(String className) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
             mNode.mClassName = className;
         }
 
         @Override
         public void setContentDescription(CharSequence contentDescription) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mContentDescription = contentDescription;
         }
 
         @Override
         public void setText(CharSequence text) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
-            mNode.mText = text;
+            final ViewNodeText t = getNodeText();
+            t.mText = TextUtils.trimNoCopySpans(text);
+            t.mTextSelectionStart = t.mTextSelectionEnd = -1;
         }
 
         @Override
         public void setText(CharSequence text, int selectionStart, int selectionEnd) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
-            mNode.mText = text;
-            // TODO(b/111276913): implement or move to superclass
+            final ViewNodeText t = getNodeText();
+            t.mText = TextUtils.trimNoCopySpans(text);
+            t.mTextSelectionStart = selectionStart;
+            t.mTextSelectionEnd = selectionEnd;
         }
 
         @Override
         public void setTextStyle(float size, int fgColor, int bgColor, int style) {
-            // TODO(b/111276913): implement or move to superclass
+            final ViewNodeText t = getNodeText();
+            t.mTextColor = fgColor;
+            t.mTextBackgroundColor = bgColor;
+            t.mTextSize = size;
+            t.mTextStyle = style;
         }
 
         @Override
         public void setTextLines(int[] charOffsets, int[] baselines) {
-            // TODO(b/111276913): implement or move to superclass
+            final ViewNodeText t = getNodeText();
+            t.mLineCharOffsets = charOffsets;
+            t.mLineBaselines = baselines;
+        }
+
+        @Override
+        public void setTextIdEntry(String entryName) {
+            mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
         }
 
         @Override
         public void setHint(CharSequence hint) {
-            // TODO(b/111276913): implement or move to superclass
+            getNodeText().mHint = hint != null ? hint.toString() : null;
         }
 
         @Override
         public CharSequence getText() {
-            // TODO(b/111276913): temporarily getting directly; should be done on superclass instead
-            return mNode.mText;
+            return mNode.getText();
         }
 
         @Override
         public int getTextSelectionStart() {
-            // TODO(b/111276913): implement or move to superclass
-            return 0;
+            return mNode.getTextSelectionStart();
         }
 
         @Override
         public int getTextSelectionEnd() {
-            // TODO(b/111276913): implement or move to superclass
-            return 0;
+            return mNode.getTextSelectionEnd();
         }
 
         @Override
         public CharSequence getHint() {
-            // TODO(b/111276913): implement or move to superclass
-            return null;
+            return mNode.getHint();
         }
 
         @Override
         public Bundle getExtras() {
-            // TODO(b/111276913): implement or move to superclass
-            return null;
+            if (mNode.mExtras != null) {
+                return mNode.mExtras;
+            }
+            mNode.mExtras = new Bundle();
+            return mNode.mExtras;
         }
 
         @Override
         public boolean hasExtras() {
-            // TODO(b/111276913): implement or move to superclass
-            return false;
+            return mNode.mExtras != null;
         }
 
         @Override
@@ -325,50 +910,64 @@
 
         @Override
         public AutofillId getAutofillId() {
-            // TODO(b/111276913): temporarily getting directly; should be done on superclass instead
             return mNode.mAutofillId;
         }
 
         @Override
         public void setAutofillId(AutofillId id) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
-            mNode.mAutofillId = id;
+            mNode.mAutofillId = Preconditions.checkNotNull(id);
         }
 
+
         @Override
         public void setAutofillId(AutofillId parentId, int virtualId) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
+            mNode.mParentAutofillId = Preconditions.checkNotNull(parentId);
             mNode.mAutofillId = new AutofillId(parentId, virtualId);
         }
 
         @Override
-        public void setAutofillType(int type) {
-            // TODO(b/111276913): implement or move to superclass
+        public void setAutofillType(@View.AutofillType int type) {
+            mNode.mAutofillType = type;
         }
 
         @Override
-        public void setAutofillHints(String[] hint) {
-            // TODO(b/111276913): implement or move to superclass
+        public void setAutofillHints(String[] hints) {
+            mNode.mAutofillHints = hints;
         }
 
         @Override
         public void setAutofillValue(AutofillValue value) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mAutofillValue = value;
         }
 
         @Override
         public void setAutofillOptions(CharSequence[] options) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mAutofillOptions = options;
         }
 
         @Override
         public void setInputType(int inputType) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mInputType = inputType;
+        }
+
+        @Override
+        public void setMinTextEms(int minEms) {
+            mNode.mMinEms = minEms;
+        }
+
+        @Override
+        public void setMaxTextEms(int maxEms) {
+            mNode.mMaxEms = maxEms;
+        }
+
+        @Override
+        public void setMaxTextLength(int maxLength) {
+            mNode.mMaxLength = maxLength;
         }
 
         @Override
         public void setDataIsSensitive(boolean sensitive) {
-            // TODO(b/111276913): implement or move to superclass
+            Log.w(TAG, "setDataIsSensitive() is not supported");
         }
 
         @Override
@@ -378,7 +977,7 @@
 
         @Override
         public Rect getTempRect() {
-            // TODO(b/111276913): implement or move to superclass
+            Log.w(TAG, "getTempRect() is not supported");
             return null;
         }
 
@@ -389,7 +988,7 @@
 
         @Override
         public void setLocaleList(LocaleList localeList) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mLocaleList = localeList;
         }
 
         @Override
@@ -402,5 +1001,66 @@
         public void setHtmlInfo(HtmlInfo htmlInfo) {
             Log.w(TAG, "setHtmlInfo() is not supported");
         }
+
+        private ViewNodeText getNodeText() {
+            if (mNode.mText != null) {
+                return mNode.mText;
+            }
+            mNode.mText = new ViewNodeText();
+            return mNode.mText;
+        }
+    }
+
+    //TODO(b/122484602): copied 'as-is' from AssistStructure, except for writeSensitive
+    static final class ViewNodeText {
+        CharSequence mText;
+        float mTextSize;
+        int mTextStyle;
+        int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
+        int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
+        int mTextSelectionStart;
+        int mTextSelectionEnd;
+        int[] mLineCharOffsets;
+        int[] mLineBaselines;
+        String mHint;
+
+        ViewNodeText() {
+        }
+
+        boolean isSimple() {
+            return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED
+                    && mTextSelectionStart == 0 && mTextSelectionEnd == 0
+                    && mLineCharOffsets == null && mLineBaselines == null && mHint == null;
+        }
+
+        ViewNodeText(Parcel in, boolean simple) {
+            mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            mTextSize = in.readFloat();
+            mTextStyle = in.readInt();
+            mTextColor = in.readInt();
+            if (!simple) {
+                mTextBackgroundColor = in.readInt();
+                mTextSelectionStart = in.readInt();
+                mTextSelectionEnd = in.readInt();
+                mLineCharOffsets = in.createIntArray();
+                mLineBaselines = in.createIntArray();
+                mHint = in.readString();
+            }
+        }
+
+        void writeToParcel(Parcel out, boolean simple) {
+            TextUtils.writeToParcel(mText, out, 0);
+            out.writeFloat(mTextSize);
+            out.writeInt(mTextStyle);
+            out.writeInt(mTextColor);
+            if (!simple) {
+                out.writeInt(mTextBackgroundColor);
+                out.writeInt(mTextSelectionStart);
+                out.writeInt(mTextSelectionEnd);
+                out.writeIntArray(mLineCharOffsets);
+                out.writeIntArray(mLineBaselines);
+                out.writeString(mHint);
+            }
+        }
     }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
index b233b75..57ed7f9 100644
--- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java
+++ b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
@@ -41,6 +41,17 @@
      */
     private static final String PROP_DEBUG_MULTI_CLIENT_IME = "persist.debug.multi_client_ime";
 
+    /**
+     * System property key for debugging purpose. The value must be empty, "1", or "0".
+     *
+     * <p>Values 'y', 'yes', '1', 'true' or 'on' are considered true.</p>
+     *
+     * <p>To set, run "adb root && adb shell setprop persist.debug.per_profile_ime 1".</p>
+     *
+     * <p>This value will be ignored when {@link Build#IS_DEBUGGABLE} returns {@code false}.</p>
+     */
+    private static final String PROP_DEBUG_PER_PROFILE_IME = "persist.debug.per_profile_ime";
+
     @Nullable
     private static ComponentName getMultiClientImeComponentName() {
         if (Build.IS_DEBUGGABLE) {
@@ -59,6 +70,9 @@
     /**
      * {@link ComponentName} of multi-client IME to be used.
      *
+     * <p>TODO: Move this back to MultiClientInputMethodManagerService once
+     * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p>
+     *
      * @hide
      */
     @Nullable
@@ -68,7 +82,19 @@
     /**
      * {@code true} when multi-client IME is enabled.
      *
+     * <p>TODO: Move this back to MultiClientInputMethodManagerService once
+     * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p>
+     *
      * @hide
      */
     public static final boolean MULTI_CLIENT_IME_ENABLED = (sMultiClientImeComponentName != null);
+
+    /**
+     * {@code true} when per-profile IME is enabled.
+     * @hide
+     */
+    public static final boolean PER_PROFILE_IME_ENABLED = MULTI_CLIENT_IME_ENABLED
+            || Build.IS_DEBUGGABLE && SystemProperties.getBoolean(
+                    PROP_DEBUG_PER_PROFILE_IME, false);
+
 }
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 4c6862c..5dc8b19 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -67,12 +67,6 @@
     private static final String TAG = TextServicesManager.class.getSimpleName();
     private static final boolean DBG = false;
 
-    /**
-     * A compile time switch to control per-profile spell checker, which is not yet ready.
-     * @hide
-     */
-    public static final boolean DISABLE_PER_PROFILE_SPELL_CHECKER = true;
-
     private static TextServicesManager sInstance;
 
     private final ITextServicesManager mService;
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 20febc2..afe46701 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -837,8 +837,8 @@
 
             mContentWidth = width;
             mContentHeight = height;
-            mOffsetX = (int) (0.1f * width);
-            mOffsetY = (int) (0.1f * height);
+            mOffsetX = (int) (1.05f * elevation);
+            mOffsetY = (int) (1.05f * elevation);
             // Setup the surface we will use for drawing the content and shadow.
             mSurfaceWidth = mContentWidth + 2 * mOffsetX;
             mSurfaceHeight = mContentHeight + 2 * mOffsetY;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0ea8579..0d16998 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3520,7 +3520,7 @@
      */
     @android.view.RemotableViewMethod
     public void setTextSelectHandle(@DrawableRes int textSelectHandle) {
-        Preconditions.checkArgumentPositive(textSelectHandle,
+        Preconditions.checkArgument(textSelectHandle != 0,
                 "The text select handle should be a valid drawable resource id.");
         setTextSelectHandle(mContext.getDrawable(textSelectHandle));
     }
@@ -3577,7 +3577,7 @@
      */
     @android.view.RemotableViewMethod
     public void setTextSelectHandleLeft(@DrawableRes int textSelectHandleLeft) {
-        Preconditions.checkArgumentPositive(textSelectHandleLeft,
+        Preconditions.checkArgument(textSelectHandleLeft != 0,
                 "The text select left handle should be a valid drawable resource id.");
         setTextSelectHandleLeft(mContext.getDrawable(textSelectHandleLeft));
     }
@@ -3634,7 +3634,7 @@
      */
     @android.view.RemotableViewMethod
     public void setTextSelectHandleRight(@DrawableRes int textSelectHandleRight) {
-        Preconditions.checkArgumentPositive(textSelectHandleRight,
+        Preconditions.checkArgument(textSelectHandleRight != 0,
                 "The text select right handle should be a valid drawable resource id.");
         setTextSelectHandleRight(mContext.getDrawable(textSelectHandleRight));
     }
@@ -3667,9 +3667,7 @@
      * @see #setTextCursorDrawable(int)
      * @attr ref android.R.styleable#TextView_textCursorDrawable
      */
-    public void setTextCursorDrawable(@NonNull Drawable textCursorDrawable) {
-        Preconditions.checkNotNull(textCursorDrawable,
-                "The cursor drawable should not be null.");
+    public void setTextCursorDrawable(@Nullable Drawable textCursorDrawable) {
         mCursorDrawable = textCursorDrawable;
         mCursorDrawableRes = 0;
         if (mEditor != null) {
@@ -3687,9 +3685,8 @@
      * @attr ref android.R.styleable#TextView_textCursorDrawable
      */
     public void setTextCursorDrawable(@DrawableRes int textCursorDrawable) {
-        Preconditions.checkArgumentPositive(textCursorDrawable,
-                "The cursor drawable should be a valid drawable resource id.");
-        setTextCursorDrawable(mContext.getDrawable(textCursorDrawable));
+        setTextCursorDrawable(
+                textCursorDrawable != 0 ? mContext.getDrawable(textCursorDrawable) : null);
     }
 
     /**
@@ -8061,6 +8058,26 @@
                     }
                 }
                 break;
+
+            case KeyEvent.KEYCODE_FORWARD_DEL:
+                if (event.hasModifiers(KeyEvent.META_SHIFT_ON) && canCut()) {
+                    if (onTextContextMenuItem(ID_CUT)) {
+                        return KEY_EVENT_HANDLED;
+                    }
+                }
+                break;
+
+            case KeyEvent.KEYCODE_INSERT:
+                if (event.hasModifiers(KeyEvent.META_CTRL_ON) && canCopy()) {
+                    if (onTextContextMenuItem(ID_COPY)) {
+                        return KEY_EVENT_HANDLED;
+                    }
+                } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON) && canPaste()) {
+                    if (onTextContextMenuItem(ID_PASTE)) {
+                        return KEY_EVENT_HANDLED;
+                    }
+                }
+                break;
         }
 
         if (mEditor != null && mEditor.mKeyListener != null) {
@@ -10831,25 +10848,6 @@
                         return onTextContextMenuItem(ID_PASTE);
                     }
                     break;
-                case KeyEvent.KEYCODE_INSERT:
-                    if (canCopy()) {
-                        return onTextContextMenuItem(ID_COPY);
-                    }
-                    break;
-            }
-        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-            // Handle Shift-only shortcuts.
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_FORWARD_DEL:
-                    if (canCut()) {
-                        return onTextContextMenuItem(ID_CUT);
-                    }
-                    break;
-                case KeyEvent.KEYCODE_INSERT:
-                    if (canPaste()) {
-                        return onTextContextMenuItem(ID_PASTE);
-                    }
-                    break;
             }
         } else if (event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
             // Handle Ctrl-Shift shortcuts.
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index e59bee4..c4ab91f 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -17,8 +17,10 @@
 package com.android.internal.app;
 
 import android.app.AppOpsManager;
+import android.app.AppOpsManager;
 import android.content.pm.ParceledListSlice;
 import android.os.Bundle;
+import android.os.RemoteCallback;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsActiveCallback;
 import com.android.internal.app.IAppOpsNotedCallback;
@@ -42,10 +44,15 @@
     int checkPackage(int uid, String packageName);
     List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
-    ParceledListSlice getAllHistoricalPackagesOps(in String[] ops,
-            long beginTimeMillis, long endTimeMillis);
-    AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int uid, String packageName,
-            in String[] ops, long beginTimeMillis, long endTimeMillis);
+    void getHistoricalOps(int uid, String packageName, in String[] ops, long beginTimeMillis,
+            long endTimeMillis, in RemoteCallback callback);
+    void getHistoricalOpsFromDiskRaw(int uid, String packageName, in String[] ops,
+            long beginTimeMillis, long endTimeMillis, in RemoteCallback callback);
+    void offsetHistory(long duration);
+    void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
+    void addHistoricalOps(in AppOpsManager.HistoricalOps ops);
+    void resetHistoryParameters();
+    void clearHistory();
     List<AppOpsManager.PackageOps> getUidOps(int uid, in int[] ops);
     void setUidMode(int code, int uid, int mode);
     void setMode(int code, int uid, String packageName, int mode);
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index c94c64a..e8ac223 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -39,6 +39,7 @@
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * Base class representing a remote service.
@@ -93,6 +94,9 @@
     // Used just for debugging purposes (on dump)
     private long mNextUnbind;
 
+    /** Requests that have been scheduled, but that are not finished yet */
+    private final ArrayList<PendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
+
     /**
      * Callback called when the service dies.
      *
@@ -229,6 +233,8 @@
                 .append(mComponentName.flattenToString()).println();
         pw.append(prefix).append(tab).append("destroyed=")
                 .append(String.valueOf(mDestroyed)).println();
+        pw.append(prefix).append(tab).append("numUnfinishedRequests=")
+                .append(String.valueOf(mUnfinishedRequests.size()));
         final boolean bound = handleIsBound();
         pw.append(prefix).append(tab).append("bound=")
                 .append(String.valueOf(bound));
@@ -257,23 +263,37 @@
      * <p>This request must be responded by the service somehow (typically using a callback),
      * othewise it will trigger a {@link PendingRequest#onTimeout(AbstractRemoteService)} if the
      * service doesn't respond.
-     *
-     * <p><b>NOTE: </b>this request is responsible for calling {@link #scheduleUnbind()}.
      */
     protected void scheduleRequest(@NonNull PendingRequest<S, I> pendingRequest) {
-        cancelScheduledUnbind();
         mHandler.sendMessage(obtainMessage(
                 AbstractRemoteService::handlePendingRequest, this, pendingRequest));
     }
 
     /**
+     * Marks a pendingRequest as finished.
+     *
+     * @param finshedRequest The request that is finished
+     */
+    void finishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+        mHandler.sendMessage(
+                obtainMessage(AbstractRemoteService::handleFinishRequest, this, finshedRequest));
+    }
+
+    private void handleFinishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+        mUnfinishedRequests.remove(finshedRequest);
+
+        if (mUnfinishedRequests.isEmpty()) {
+            scheduleUnbind();
+        }
+    }
+
+    /**
      * Schedules an async request.
      *
      * <p>This request is not expecting a callback from the service, hence it's represented by
      * a simple {@link Runnable}.
      */
     protected void scheduleAsyncRequest(@NonNull AsyncRequest<I> request) {
-        scheduleUnbind();
         // TODO(b/117779333): fix generics below
         @SuppressWarnings({"unchecked", "rawtypes"})
         final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request);
@@ -341,6 +361,10 @@
             handleEnsureBound();
         } else {
             if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest);
+
+            mUnfinishedRequests.add(pendingRequest);
+            cancelScheduledUnbind();
+
             pendingRequest.run();
             if (pendingRequest.isFinal()) {
                 mCompleted = true;
@@ -504,6 +528,12 @@
                 }
                 mCompleted = true;
             }
+
+            S service = mWeakService.get();
+            if (service != null) {
+                service.finishRequest(this);
+            }
+
             mServiceHandler.removeCallbacks(mTimeoutTrigger);
             return true;
         }
diff --git a/core/java/com/android/internal/os/AtomicDirectory.java b/core/java/com/android/internal/os/AtomicDirectory.java
new file mode 100644
index 0000000..f24d12e
--- /dev/null
+++ b/core/java/com/android/internal/os/AtomicDirectory.java
@@ -0,0 +1,294 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.FileUtils;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Helper class for performing atomic operations on a directory, by creating a
+ * backup directory until a write has successfully completed.
+ * <p>
+ * Atomic directory guarantees directory integrity by ensuring that a directory has
+ * been completely written and sync'd to disk before removing its backup.
+ * As long as the backup directory exists, the original directory is considered
+ * to be invalid (leftover from a previous attempt to write).
+ * <p>
+ * Atomic directory does not confer any file locking semantics. Do not use this
+ * class when the directory may be accessed or modified concurrently
+ * by multiple threads or processes. The caller is responsible for ensuring
+ * appropriate mutual exclusion invariants whenever it accesses the directory.
+ * <p>
+ * To ensure atomicity you must always use this class to interact with the
+ * backing directory when checking existence, making changes, and deleting.
+ */
+public final class AtomicDirectory {
+    private final @NonNull ArrayMap<File, FileOutputStream> mOpenFiles = new ArrayMap<>();
+    private final @NonNull File mBaseDirectory;
+    private final @NonNull File mBackupDirectory;
+
+    private int mBaseDirectoryFd = -1;
+    private int mBackupDirectoryFd = -1;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param baseDirectory The base directory to treat atomically.
+     */
+    public AtomicDirectory(@NonNull File baseDirectory) {
+        Preconditions.checkNotNull(baseDirectory, "baseDirectory cannot be null");
+        mBaseDirectory = baseDirectory;
+        mBackupDirectory = new File(baseDirectory.getPath() + "_bak");
+    }
+
+    /**
+     * Gets the backup directory if present. This could be useful if you are
+     * writing new state to the dir but need to access the last persisted state
+     * at the same time. This means that this call is useful in between
+     * {@link #startWrite()} and {@link #finishWrite()} or {@link #failWrite()}.
+     * You should not modify the content returned by this method.
+     *
+     * @see #startRead()
+     */
+    public @Nullable File getBackupDirectory() {
+        return mBackupDirectory;
+    }
+
+    /**
+     * Starts reading this directory. After calling this method you should
+     * not make any changes to its contents.
+     *
+     * @throws IOException If an error occurs.
+     *
+     * @see #finishRead()
+     * @see #startWrite()
+     */
+    public @NonNull File startRead() throws IOException {
+        restore();
+        return getOrCreateBaseDirectory();
+    }
+
+    /**
+     * Finishes reading this directory.
+     *
+     * @see #startRead()
+     * @see #startWrite()
+     */
+    public void finishRead() {
+        mBaseDirectoryFd = -1;
+        mBackupDirectoryFd = -1;
+    }
+
+    /**
+     * Starts editing this directory. After calling this method you should
+     * add content to the directory only via the APIs on this class. To open a
+     * file for writing in this directory you should use {@link #openWrite(File)}
+     * and to close the file {@link #closeWrite(FileOutputStream)}. Once all
+     * content has been written and all files closed you should commit via a
+     * call to {@link #finishWrite()} or discard via a call to {@link #failWrite()}.
+     *
+     * @throws IOException If an error occurs.
+     *
+     * @see #startRead()
+     * @see #openWrite(File)
+     * @see #finishWrite()
+     * @see #failWrite()
+     */
+    public @NonNull File startWrite() throws IOException {
+        backup();
+        return getOrCreateBaseDirectory();
+    }
+
+    /**
+     * Opens a file in this directory for writing.
+     *
+     * @param file The file to open. Must be a file in the base directory.
+     * @return An input stream for reading.
+     *
+     * @throws IOException If an I/O error occurs.
+     *
+     * @see #closeWrite(FileOutputStream)
+     */
+    public @NonNull FileOutputStream openWrite(@NonNull File file) throws IOException {
+        if (file.isDirectory() || !file.getParentFile().equals(getOrCreateBaseDirectory())) {
+            throw new IllegalArgumentException("Must be a file in " + getOrCreateBaseDirectory());
+        }
+        final FileOutputStream destination = new FileOutputStream(file);
+        if (mOpenFiles.put(file, destination) != null) {
+            throw new IllegalArgumentException("Already open file" + file.getCanonicalPath());
+        }
+        return destination;
+    }
+
+    /**
+     * Closes a previously opened file.
+     *
+     * @param destination The stream to the file returned by {@link #openWrite(File)}.
+     *
+     * @see #openWrite(File)
+     */
+    public void closeWrite(@NonNull FileOutputStream destination) {
+        final int indexOfValue = mOpenFiles.indexOfValue(destination);
+        if (mOpenFiles.removeAt(indexOfValue) == null) {
+            throw new IllegalArgumentException("Unknown file stream " + destination);
+        }
+        FileUtils.sync(destination);
+        try {
+            destination.close();
+        } catch (IOException ignored) {}
+    }
+
+    public void failWrite(@NonNull FileOutputStream destination) {
+        final int indexOfValue = mOpenFiles.indexOfValue(destination);
+        if (indexOfValue >= 0) {
+            mOpenFiles.removeAt(indexOfValue);
+        }
+    }
+
+    /**
+     * Finishes the edit and commits all changes.
+     *
+     * @see #startWrite()
+     *
+     * @throws IllegalStateException is some files are not closed.
+     */
+    public void finishWrite() {
+        throwIfSomeFilesOpen();
+        fsyncDirectoryFd(mBaseDirectoryFd);
+        deleteDirectory(mBackupDirectory);
+        fsyncDirectoryFd(mBackupDirectoryFd);
+        mBaseDirectoryFd = -1;
+        mBackupDirectoryFd = -1;
+    }
+
+    /**
+     * Finishes the edit and discards all changes.
+     *
+     * @see #startWrite()
+     */
+    public void failWrite() {
+        throwIfSomeFilesOpen();
+        try{
+            restore();
+        } catch (IOException ignored) {}
+        mBaseDirectoryFd = -1;
+        mBackupDirectoryFd = -1;
+    }
+
+    /**
+     * @return Whether this directory exists.
+     */
+    public boolean exists() {
+        return mBaseDirectory.exists() || mBackupDirectory.exists();
+    }
+
+    /**
+     * Deletes this directory.
+     */
+    public void delete() {
+        if (mBaseDirectory.exists()) {
+            deleteDirectory(mBaseDirectory);
+            fsyncDirectoryFd(mBaseDirectoryFd);
+        }
+        if (mBackupDirectory.exists()) {
+            deleteDirectory(mBackupDirectory);
+            fsyncDirectoryFd(mBackupDirectoryFd);
+        }
+    }
+
+    private @NonNull File getOrCreateBaseDirectory() throws IOException {
+        if (!mBaseDirectory.exists()) {
+            if (!mBaseDirectory.mkdirs()) {
+                throw new IOException("Couldn't create directory " + mBaseDirectory);
+            }
+            FileUtils.setPermissions(mBaseDirectory.getPath(),
+                    FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH,
+                    -1, -1);
+        }
+        if (mBaseDirectoryFd < 0) {
+            mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath());
+        }
+        return mBaseDirectory;
+    }
+
+    private void throwIfSomeFilesOpen() {
+        if (!mOpenFiles.isEmpty()) {
+            throw new IllegalStateException("Unclosed files: "
+                    + Arrays.toString(mOpenFiles.keySet().toArray()));
+        }
+    }
+
+    private void backup() throws IOException {
+        if (!mBaseDirectory.exists()) {
+            return;
+        }
+        if (mBaseDirectoryFd < 0) {
+            mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath());
+        }
+        if (mBackupDirectory.exists()) {
+            deleteDirectory(mBackupDirectory);
+        }
+        if (!mBaseDirectory.renameTo(mBackupDirectory)) {
+            throw new IOException("Couldn't backup " + mBaseDirectory
+                    + " to " + mBackupDirectory);
+        }
+        mBackupDirectoryFd = mBaseDirectoryFd;
+        mBaseDirectoryFd = -1;
+        fsyncDirectoryFd(mBackupDirectoryFd);
+    }
+
+    private void restore() throws IOException {
+        if (!mBackupDirectory.exists()) {
+            return;
+        }
+        if (mBackupDirectoryFd == -1) {
+            mBackupDirectoryFd = getDirectoryFd(mBackupDirectory.getCanonicalPath());
+        }
+        if (mBaseDirectory.exists()) {
+            deleteDirectory(mBaseDirectory);
+        }
+        if (!mBackupDirectory.renameTo(mBaseDirectory)) {
+            throw new IOException("Couldn't restore " + mBackupDirectory
+                    + " to " + mBaseDirectory);
+        }
+        mBaseDirectoryFd = mBackupDirectoryFd;
+        mBackupDirectoryFd = -1;
+        fsyncDirectoryFd(mBaseDirectoryFd);
+    }
+
+    private static void deleteDirectory(@NonNull File file) {
+        final File[] children = file.listFiles();
+        if (children != null) {
+            for (File child : children) {
+                deleteDirectory(child);
+            }
+        }
+        file.delete();
+    }
+
+    private static native int getDirectoryFd(String path);
+    private static native void fsyncDirectoryFd(int fd);
+}
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index 100c6ee..adf7692 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -16,10 +16,10 @@
 
 package com.android.internal.policy;
 
-import com.android.internal.R;
-
 import android.content.res.Resources;
 
+import com.android.internal.R;
+
 /**
  * Utility functions for screen decorations used by both window manager and System UI.
  */
@@ -31,15 +31,19 @@
      * scaling, this means that we don't have to reload them on config changes.
      */
     public static float getWindowCornerRadius(Resources resources) {
+        if (!supportsRoundedCornersOnWindows(resources)) {
+            return 0f;
+        }
+
         // Radius that should be used in case top or bottom aren't defined.
         float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius);
 
         float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top);
-        if (topRadius == 0) {
+        if (topRadius == 0f) {
             topRadius = defaultRadius;
         }
         float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom);
-        if (bottomRadius == 0) {
+        if (bottomRadius == 0f) {
             bottomRadius = defaultRadius;
         }
 
@@ -47,4 +51,11 @@
         // completely cover the display.
         return Math.min(topRadius, bottomRadius);
     }
+
+    /**
+     * If live rounded corners are supported on windows.
+     */
+    public static boolean supportsRoundedCornersOnWindows(Resources resources) {
+        return resources.getBoolean(R.bool.config_supportsRoundedCornersOnWindows);
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 53b56f2..6a28059 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -153,13 +153,11 @@
     void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
             boolean requireConfirmation, int userId);
     // Used to hide the dialog when a biometric is authenticated
-    void onBiometricAuthenticated();
+    void onBiometricAuthenticated(boolean authenticated);
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
     void onBiometricHelp(String message);
     // Used to set a message - the dialog will dismiss after a certain amount of time
     void onBiometricError(String error);
     // Used to hide the biometric dialog when the AuthenticationClient is stopped
     void hideBiometricDialog();
-    // Used to request the "try again" button for authentications which requireConfirmation=true
-    void showBiometricTryAgain();
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 9087dd2..197e873 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -97,13 +97,11 @@
     void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
             boolean requireConfirmation, int userId);
     // Used to hide the dialog when a biometric is authenticated
-    void onBiometricAuthenticated();
+    void onBiometricAuthenticated(boolean authenticated);
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
     void onBiometricHelp(String message);
     // Used to set a message - the dialog will dismiss after a certain amount of time
     void onBiometricError(String error);
     // Used to hide the biometric dialog when the AuthenticationClient is stopped
     void hideBiometricDialog();
-    // Used to request the "try again" button for authentications which requireConfirmation=true
-    void showBiometricTryAgain();
 }
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 470533f2..605df04 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -330,4 +330,18 @@
     public static @NonNull <T> List<T> defeatNullable(@Nullable List<T> val) {
         return (val != null) ? val : Collections.emptyList();
     }
+
+    /**
+     * @return the first element if not empty/null, null otherwise
+     */
+    public static @Nullable <T> T firstOrNull(@Nullable List<T> cur) {
+        return isEmpty(cur) ? null : cur.get(0);
+    }
+
+    /**
+     * @return list of single given element if it's not null, empty list otherwise
+     */
+    public static @NonNull <T> List<T> singletonOrEmpty(@Nullable T item) {
+        return item == null ? Collections.emptyList() : Collections.singletonList(item);
+    }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index dc6a73a..088e13f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -41,7 +41,7 @@
         "com_google_android_gles_jni_EGLImpl.cpp",
         "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm
         "android_app_Activity.cpp",
-	"android_app_ActivityThread.cpp",
+        "android_app_ActivityThread.cpp",
         "android_app_NativeActivity.cpp",
         "android_app_admin_SecurityLog.cpp",
         "android_opengl_EGL14.cpp",
@@ -202,6 +202,7 @@
         "android_animation_PropertyValuesHolder.cpp",
         "android_security_Scrypt.cpp",
         "com_android_internal_net_NetworkStatsFactory.cpp",
+        "com_android_internal_os_AtomicDirectory.cpp",
         "com_android_internal_os_ClassLoaderFactory.cpp",
         "com_android_internal_os_FuseAppLoop.cpp",
         "com_android_internal_os_Zygote.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 687b105..1092222 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -218,6 +218,7 @@
 extern int register_android_security_Scrypt(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_AtomicDirectory(JNIEnv *env);
 extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
 extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
@@ -1495,6 +1496,7 @@
     REG_JNI(register_android_security_Scrypt),
     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
     REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
+    REG_JNI(register_com_android_internal_os_AtomicDirectory),
     REG_JNI(register_com_android_internal_os_FuseAppLoop),
 };
 
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 163b86b..42e3942 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -329,7 +329,7 @@
         return NULL;
     }
 
-    LOG(INFO) << "HwBinder: Starting thread pool for " << serviceName << "::" << ifaceName;
+    LOG(INFO) << "HwBinder: Starting thread pool for getting: " << ifaceName << "/" << serviceName;
     ::android::hardware::ProcessState::self()->startThreadPool();
 
     return JHwRemoteBinder::NewObject(env, service);
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index ecf8119..50cff5c 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -334,7 +334,7 @@
 static jlong android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz,
         jlong nativePtr,
         jint deviceId, jint source, jint displayId, jint action, jint flags, jint edgeFlags,
-        jint metaState, jint buttonState,
+        jint metaState, jint buttonState, jint classification,
         jfloat xOffset, jfloat yOffset, jfloat xPrecision, jfloat yPrecision,
         jlong downTimeNanos, jlong eventTimeNanos,
         jint pointerCount, jobjectArray pointerPropertiesObjArray,
@@ -373,7 +373,8 @@
     }
 
     event->initialize(deviceId, source, displayId, action, 0, flags, edgeFlags, metaState,
-            buttonState, xOffset, yOffset, xPrecision, yPrecision,
+            buttonState, static_cast<MotionClassification>(classification),
+            xOffset, yOffset, xPrecision, yPrecision,
             downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
 
     return reinterpret_cast<jlong>(event);
@@ -668,6 +669,11 @@
     event->setButtonState(buttonState);
 }
 
+static jint android_view_MotionEvent_nativeGetClassification(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return static_cast<jint>(event->getClassification());
+}
+
 static void android_view_MotionEvent_nativeOffsetLocation(jlong nativePtr, jfloat deltaX,
         jfloat deltaY) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -747,7 +753,7 @@
 static const JNINativeMethod gMotionEventMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInitialize",
-            "(JIIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
+            "(JIIIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
                     "[Landroid/view/MotionEvent$PointerCoords;)J",
             (void*)android_view_MotionEvent_nativeInitialize },
     { "nativeDispose",
@@ -846,6 +852,9 @@
     { "nativeSetButtonState",
             "(JI)V",
             (void*)android_view_MotionEvent_nativeSetButtonState },
+    { "nativeGetClassification",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetClassification },
     { "nativeOffsetLocation",
             "(JFF)V",
             (void*)android_view_MotionEvent_nativeOffsetLocation },
diff --git a/core/jni/com_android_internal_os_AtomicDirectory.cpp b/core/jni/com_android_internal_os_AtomicDirectory.cpp
new file mode 100644
index 0000000..50b2288
--- /dev/null
+++ b/core/jni/com_android_internal_os_AtomicDirectory.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#include <nativehelper/ScopedUtfChars.h>
+#include "jni.h"
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static jint com_android_internal_os_AtomicDirectory_getDirectoryFd(JNIEnv* env,
+        jobject /*clazz*/, jstring path) {
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        ALOGE("Invalid path: %s", path8.c_str());
+        return -1;
+    }
+    int fd;
+    if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY))) == -1) {
+        ALOGE("Cannot open directory %s, error: %s\n", path8.c_str(), strerror(errno));
+        return -1;
+    }
+    return fd;
+}
+
+static void com_android_internal_os_AtomicDirectory_fsyncDirectoryFd(JNIEnv* env,
+        jobject /*clazz*/, jint fd) {
+    if (TEMP_FAILURE_RETRY(fsync(fd)) == -1) {
+        ALOGE("Cannot fsync directory %d, error: %s\n", fd, strerror(errno));
+    }
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gRegisterMethods[] = {
+    /* name, signature, funcPtr */
+    { "fsyncDirectoryFd",
+      "(I)V",
+       (void*) com_android_internal_os_AtomicDirectory_fsyncDirectoryFd
+    },
+    { "getDirectoryFd",
+      "(Ljava/lang/String;)I",
+       (void*) com_android_internal_os_AtomicDirectory_getDirectoryFd
+    },
+};
+
+int register_com_android_internal_os_AtomicDirectory(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "com/android/internal/os/AtomicDirectory",
+            gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
diff --git a/core/proto/android/app/window_configuration.proto b/core/proto/android/app/window_configuration.proto
index 2d15552..6cc1a40 100644
--- a/core/proto/android/app/window_configuration.proto
+++ b/core/proto/android/app/window_configuration.proto
@@ -29,4 +29,5 @@
     optional .android.graphics.RectProto app_bounds = 1;
     optional int32 windowing_mode = 2;
     optional int32 activity_type = 3;
+    optional .android.graphics.RectProto bounds = 4;
 }
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index a00fde9..cc5aa20 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -1018,7 +1018,9 @@
 
     optional SettingProto zram_enabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    optional SettingProto app_ops_constants = 148 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 148;
+    // Next tag = 149;
 }
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
new file mode 100644
index 0000000..b70bb67
--- /dev/null
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package com.android.server.connectivity;
+option java_multiple_files = true;
+option java_outer_classname = "DataStallEventProto";
+
+enum ProbeResult {
+    UNKNOWN = 0;
+    VALID = 1;
+    INVALID = 2;
+    PORTAL = 3;
+}
+
+enum ApBand {
+    AP_BAND_UNKNOWN = 0;
+    AP_BAND_2GHZ = 1;
+    AP_BAND_5GHZ = 2;
+}
+
+// Refer to definition in ServiceState.java.
+enum RadioTech {
+  RADIO_TECHNOLOGY_UNKNOWN = 0;
+  RADIO_TECHNOLOGY_GPRS = 1;
+  RADIO_TECHNOLOGY_EDGE = 2;
+  RADIO_TECHNOLOGY_UMTS = 3;
+  RADIO_TECHNOLOGY_IS95A = 4;
+  RADIO_TECHNOLOGY_IS95B = 5;
+  RADIO_TECHNOLOGY_1xRTT = 6;
+  RADIO_TECHNOLOGY_EVDO_0 = 7;
+  RADIO_TECHNOLOGY_EVDO_A = 8;
+  RADIO_TECHNOLOGY_HSDPA = 9;
+  RADIO_TECHNOLOGY_HSUPA = 10;
+  RADIO_TECHNOLOGY_HSPA = 11;
+  RADIO_TECHNOLOGY_EVDO_B = 12;
+  RADIO_TECHNOLOGY_EHRPD = 13;
+  RADIO_TECHNOLOGY_LTE = 14;
+  RADIO_TECHNOLOGY_HSPAP = 15;
+  RADIO_TECHNOLOGY_GSM = 16;
+  RADIO_TECHNOLOGY_TD_SCDMA = 17;
+  RADIO_TECHNOLOGY_IWLAN = 18;
+  RADIO_TECHNOLOGY_LTE_CA = 19;
+  RADIO_TECHNOLOGY_NR = 20;
+}
+
+// Cellular specific information.
+message CellularData {
+    // Indicate the radio technology at the time of data stall suspected.
+    optional RadioTech rat_type = 1;
+    // True if device is in roaming network at the time of data stall suspected.
+    optional bool is_roaming = 2;
+    // Registered network MccMnc when data stall happen
+    optional string network_mccmnc = 3;
+    // Indicate the SIM card carrier.
+    optional string sim_mccmnc = 4;
+    // Signal strength level at the time of data stall suspected.
+    optional int32 signal_strength = 5;
+}
+
+// Wifi specific information.
+message WifiData {
+    // Signal strength at the time of data stall suspected.
+    // RSSI range is between -55 to -110.
+    optional int32 signal_strength = 1;
+    // AP band.
+    optional ApBand wifi_band = 2;
+}
+
+message DnsEvent {
+    // The dns return code.
+    repeated int32 dns_return_code = 1;
+    // Indicate the timestamp of the dns event.
+    repeated int64 dns_time = 2;
+}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 449a7b3..8147b4a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3861,7 +3861,7 @@
 
     <!-- @SystemApi @hide Allows managing apk level rollbacks. -->
     <permission android:name="android.permission.MANAGE_ROLLBACKS"
-        android:protectionLevel="signature|installer" />
+        android:protectionLevel="signature|verifier" />
 
     <!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
     <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
@@ -3906,7 +3906,8 @@
     <permission android:name="android.permission.ACCESS_NOTIFICATIONS"
         android:protectionLevel="signature|privileged|appop" />
 
-    <!-- Marker permission for applications that wish to access notification policy.
+    <!-- Marker permission for applications that wish to access notification policy. This permission
+        is not supported on managed profiles.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
@@ -4254,6 +4255,16 @@
     <permission android:name="android.permission.MANAGE_CONTENT_CAPTURE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to manage the content suggestions service.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS"
+         android:protectionLevel="signature" />
+
+    <!-- @SystemApi Allows an application to manage the app predictions service.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_APP_PREDICTIONS"
+         android:protectionLevel="signature" />
+
     <!-- Allows an app to set the theme overlay in /vendor/overlay
          being used.
          @hide  <p>Not for use by third-party applications.</p> -->
@@ -4334,6 +4345,11 @@
     <permission android:name="android.permission.BIND_SMS_APP_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @hide Permission that allows configuring appops.
+     <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_APPOPS"
+                android:protectionLevel="signature" />
+
     <!-- @hide Permission that allows background clipboard access.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 3f23da6..c4616c5 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Maak oop met"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Maak oop met %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Maak oop"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Gee toegang tot oop <xliff:g id="HOST">%1$s</xliff:g>-skakels met"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Gee toegang tot oop <xliff:g id="HOST">%1$s</xliff:g>-skakels met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Verleen toegang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redigeer met"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigeer met %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Wysig"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aanvaar oproep?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altyd"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Net een keer"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s steun nie werkprofiel nie"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurkorreksie"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> afgeskakel"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik weer toeganklikheidskortpad om die huidige toeganklikheidskenmerk te begin"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies \'n kenmerk om te gebruik wanneer jy op die Toeganklikheid-knoppie tik:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Raak en hou die Toeganklikheid-knoppie om kenmerke te verander."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wys tans bo-oor ander programme op jou skerm"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Roetinemodus-inligtingkennisgewing"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery kan afloop voordat dit normaalweg gelaai word"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterybespaarder is geaktiveer om batterylewe te verleng"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Laai tans"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ca1aabd..25c23b2 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ክፈት በ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"ክፈት በ%1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ክፈት"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"የ<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን በዚህ ለመክፈት መዳረሻ ይስጡ፦"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"የ<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን በ<xliff:g id="APPLICATION">%2$s</xliff:g> ለመክፈት መዳረሻ ይስጡ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"መዳረሻ ስጥ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ያርትዑ በ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ያርትዑ በ%1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ያርትዑ"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ጥሪ ተቀበል?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ዘወትር"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"አንዴ ብቻ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ቅንብሮች"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s የስራ መገለጫ አይደግፍም"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ጡባዊ ተኮ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ቴሌቪዥን"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"የቀለም ማስተካከያ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አብርቶታል"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አጥፍቶታል"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"አሁን ያለውን የተደራሽነት ባህሪ ለመጀመር እንደገና የተደራሽነት አቋራጭን ይጠቀሙ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"የተደራሽነት አዝራርን መታ በሚያደርጉበት ጊዜ ጥቅም ላይ የሚውለውን ባህሪ ይምረጡ፦"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ባህሪያትን ለመለወጥ የተደራሽነት አዝራሩን ይንኩ እና ይያዙት።"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ማጉላት"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ካሜራ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ማይክሮፎን"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"በማያዎ ላይ በሌሎች መተግበሪያዎች ላይ በማሳየት ላይ"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"በመጫን ላይ"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4557563..25902bb 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1208,6 +1208,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"فتح باستخدام"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏فتح باستخدام %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"فتح"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"منح إمكانية الوصول لفتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"منح إمكانية الوصول لفتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"منح إذن الوصول"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"تعديل باستخدام"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏تعديل باستخدام %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"تعديل"</string>
@@ -1658,6 +1661,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"هل تريد قبول المكالمة؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"دومًا"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"مرة واحدة فقط"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"الإعدادات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏لا يدعم %1$s الملفات الشخصية للعمل"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"الجهاز اللوحي"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"التلفزيون"</string>
@@ -1741,7 +1745,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"تصحيح الألوان"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"شغَّل اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"أوقف اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"استخدِم اختصار إمكانية الوصول لبدء ميزة إمكانية الوصول الحالية."</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"يمكنك اختيار إحدى الميزات لاستخدامها عند النقر على زر إمكانية الوصول:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"لتغيير الميزات، يمكنك لمس زر \"إمكانية الوصول\" مع الاستمرار."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"التكبير"</string>
@@ -2115,5 +2119,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"كاميرا"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ميكروفون"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"العرض فوق التطبيقات الأخرى على شاشتك"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"إشعار معلومات \"وضع سلسلة الإجراءات\""</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"قد تنفد طاقة البطارية قبل الشحن المعتاد"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"تم تفعيل \"توفير شحن البطارية\" لإطالة عمرها."</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"جارٍ التحميل"</string>
 </resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a4f950a..12d9677 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ইয়াৰ জৰিয়তে খোলক"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sৰ জৰিয়তে খোলক"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"খোলক"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ইয়াৰ দ্বাৰা <xliff:g id="HOST">%1$s</xliff:g> লিংক খুলিবলৈ এক্সেছ দিয়ক"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>ৰ দ্বাৰা <xliff:g id="HOST">%1$s</xliff:g> লিংক খুলিবলৈ এক্সেছ দিয়ক"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"এক্সেছ দিয়ক"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ইয়াৰ দ্বাৰা সম্পাদনা কৰক"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sৰদ্বাৰা সম্পাদনা কৰক"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"সম্পাদনা কৰক"</string>
@@ -1257,7 +1260,7 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইন্টাৰনেট নাই"</string>
+    <string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইণ্টাৰনেট নাই"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"অধিক বিকল্পৰ বাবে টিপক"</string>
     <string name="wifi_softap_config_change" msgid="8475911871165857607">"আপোনাৰ হটস্পট ছেটিংসমূহত কৰা সালসলনি"</string>
     <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"আপোনাৰ হটস্পটৰ বেণ্ড সলনি কৰা হ’ল।"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"কল স্বীকাৰ কৰিবনে?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"সদায়"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"মাত্ৰ এবাৰ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ছেটিংসমূহ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sএ কৰ্মস্থানৰ প্ৰ\'ফাইল সমৰ্থন নকৰে।"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"টেবলেট"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ৰং শুধৰণী"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অন কৰিছে"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অফ কৰিছে"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমানৰ সাধ্য সুবিধাসমূহৰ আৰম্ভ কৰিবলৈ সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট পুনৰ ব্যৱহাৰ কৰক"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"আপুনি দিব্যাংগসকলৰ সুবিধাৰ বুটামটো টিপিলে ব্যৱহাৰ কৰিবলগীয়া কোনো সুবিধা বাছক:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"সুবিধাসমূহ সলনি কৰিবলৈ দিব্যাংগসকলৰ সুবিধাৰ বুটামটো স্পৰ্শ কৰি থাকক।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বিবৰ্ধন"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"কেমেৰা"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"মাইক্ৰ\'ফ\'ন"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"স্ক্ৰীণত অইন এপৰ ওপৰত দেখুৱাওক"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"ল’ড হৈ আছে"</string>
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 076ea8d..1bcce98 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Bununla açın"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ilə açın"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Açın"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Bu tətbiqlə <xliff:g id="HOST">%1$s</xliff:g> linklərini açmağa icazə verin:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ilə <xliff:g id="HOST">%1$s</xliff:g> linklərini açmağa icazə verin"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"İcazə verin"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bununla düzəliş edin:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ilə düzəliş edin"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redaktə edin"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Zəngi qəbul edək?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Həmişə"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Sadəcə bir dəfə"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s iş profilini dəstəkləmir"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planşet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Rəng korreksiyası"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv etdi"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini deaktiv etdi"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Cari əlçatımlılıq funksiyasını yenidən başlatmaq üçün Əlçatımlılıq Qısayolundan istifadə edin"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Əlçatımlılıq düyməsinə kliklədikdə istifadə etmək üçün funksiya seçin:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyaları dəyişmək üçün Əlçatımlılıq düyməsinə basıb saxlayın."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Böyütmə"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ekrandakı digər tətbiqlərdə göstərin"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Rejim üçün məlumat bildirişi"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batareya həmişəki vaxtdan əvvəl bitə bilər"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Enerjiyə Qənaət rejimi batareya istifadəsinin müddətini artırmaq üçün aktiv edilir"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Yüklənir"</string>
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0a94acf..57ee03d 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1148,6 +1148,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvorite pomoću"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvorite pomoću aplikacije %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dozvolite da se linkovi <xliff:g id="HOST">%1$s</xliff:g> otvaraju pomoću"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dozvolite da <xliff:g id="APPLICATION">%2$s</xliff:g> otvara linikove <xliff:g id="HOST">%1$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Izmenite pomoću"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Izmenite pomoću aplikacije %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Izmeni"</string>
@@ -1589,6 +1592,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Želite li da prihvatite poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvek"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Podešavanja"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1673,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boja"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Upotrebite ponovo prečicu za pristupačnost da biste pokrenuli aktuelnu funkciju pristupačnosti"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izaberite funkciju koja će se koristiti kada dodirnete dugme za pristupačnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pritisnite i zadržite dugme za pristupačnost da biste menjali funkcije."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
@@ -2010,5 +2014,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazuje se na ekranu dok koristite druge aplikacije"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Obaveštenje o informacijama Rutinskog režima"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterija će se možda isprazniti pre uobičajenog punjenja"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Ušteda baterije je aktivirana da bi se produžilo trajanje baterije"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Učitava se"</string>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index cfe076d..77de542 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -79,7 +79,7 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Налады ідэнтыфікатару АВН па змаўчанні: не абмяжавана. Наступны выклік: не абмежавана"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Служба не прадастаўляецца."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Вы не можаце змяніць налады ідэнтыфікатара абанента, якi тэлефануе."</string>
-    <string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Мабільны інтэрнэт недаступны"</string>
+    <string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Мабільная перадача даных недаступная"</string>
     <string name="RestrictedOnEmergencyTitle" msgid="6855466023161191166">"Экстранныя выклікі недаступныя"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Няма сэрвісу галасавых выклікаў"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="8037246983606545202">"Галасавыя або экстранныя выклікі недаступныя"</string>
@@ -435,7 +435,7 @@
     <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Акрамя доступу да прыкладнага ці дакладнага месцазнаходжання праграма можа мець доступ да вызначэння геалакацыі ў фонавым рэжыме працы. На гэта патрабуецца дазвол."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змяняць налады аудыё"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Дазваляе прыкладанням змяняць глабальныя налады гуку, такія як моц і тое, што дынамік выкарыстоўваецца для выхаду."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"запісваць аўдыё"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"запіс аўдыя"</string>
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"Гэта праграма можа у любы час запісваць аўдыя, выкарыстоўваючы мікрафон."</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"адпраўляць каманды на SIM-карту"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Дазваляе праграме адпраўляць каманды SIM-карце. Гэта вельмі небяспечна."</string>
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Адкрыць з дапамогай"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Адкрыць з дапамогай %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Адкрыць"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Адкрываць спасылкі на сэрвіс <xliff:g id="HOST">%1$s</xliff:g> з дапамогай"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Адкрываць спасылкі на сэрвіс <xliff:g id="HOST">%1$s</xliff:g> з дапамогай праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\""</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даць доступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Рэдагаваць з дапамогай"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Рэдагаваць з дапамогай %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Рэдагаваць"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Заўсёды"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Толькі адзін раз"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налады"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не падтрымлівае працоўны профіль"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшэт"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТБ"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Карэкцыя колеру"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў уключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў адключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Каб запусціць функцыю спецыяльных магчымасцей, паўторна скарыстайце ярлык спецыяльных магчымасцей"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберыце функцыю для выкарыстання пры націску кнопкі \"Спецыяльныя магчымасці\":"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Каб змяняць функцыі, краніце і ўтрымлівайце кнопку \"Спецыяльныя магчымасці\"."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Павелічэнне"</string>
@@ -2045,5 +2049,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Мікрафон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"паказваецца паверх іншых праграм на экране"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Загрузка"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8897bac..a360eae 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отваряне чрез"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отваряне чрез %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отваряне"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Предоставяне на достъп за отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> с(ъс)"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Предоставяне на достъп за отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> с(ъс) <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даване на достъп"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редактиране чрез"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактиране чрез %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Редактиране"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Да се приеме ли обаждането?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Винаги"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само веднъж"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддържа служебен потребителски профил"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Коригиране на цветовете"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Прекият път за достъпност включи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Прекият път за достъпност изключи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Използвайте отново прекия път към функцията за достъпност, за да стартирате текущата"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функция, която да използвате, когато докоснете бутона за достъпност:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За да промените функции, докоснете и задръжте бутона за достъпност."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ниво на мащаба"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"се показва върху други приложения на екрана"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Зарежда се"</string>
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 26a3ba0..ea53d19 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"এর মাধ্যমে খুলুন"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s দিয়ে খুলুন"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"খুলুন"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ব্যবহার করে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্ক খুলতে অ্যাক্সেস দিন"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ব্যবহার করে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্ক খুলতে অ্যাক্সেস দিন"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"অ্যাক্সেস দিন"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"এর মাধ্যমে সম্পাদনা করুন"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s দিয়ে সম্পাদনা করুন"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"সম্পাদনা করুন"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"কল গ্রহণ করবেন?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"সবসময়"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"শুধু একবার"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"সেটিংস"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s কর্মস্থলের প্রোফাইল সমর্থন করে না।"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ট্যাবলেট"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"রঙ সংশোধন"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে চালু করেছে"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে বন্ধ করেছে"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমান অ্যাক্সেসিবিলিটি বৈশিষ্ট্য শুরু করার জন্য অ্যাক্সেসিবিলিটি শর্টকাটটি আবার ব্যবহার করুন"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"অ্যাক্সেসযোগ্যতা বোতামের সাহায্যে যে বৈশিষ্ট্যটি নিয়ন্ত্রণ করতে চান, সেটি বেছে নিন:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"বৈশিষ্ট্যগুলি পরিবর্তন করতে অ্যাক্সেসযোগ্যতা বোতামটি ট্যাপ করে ধরে রাখুন।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বড় করে দেখা"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ক্যামেরা"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"মাইক্রোফোন"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"স্ক্রিনে অন্যান্য অ্যাপের উপরে দেখানো হচ্ছে"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"লোড হচ্ছে"</string>
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index e336cd0..a3d2ac3 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1148,6 +1148,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvori koristeći"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvori koristeći %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dozvolite pristup za otvaranje linkova hosta <xliff:g id="HOST">%1$s</xliff:g> pomoću"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dozvolite pristup za otvaranje linkova hosta <xliff:g id="HOST">%1$s</xliff:g> pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Uredi koristeći"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Uredi"</string>
@@ -1591,6 +1594,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo ovaj put"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1671,7 +1675,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Ispravka boja"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo koristite Prečicu za pristupačnost da započnete trenutnu funkciju pristupačnosti"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da promijenite funkcije, dodirnite i držite dugme Pristupačnost."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
@@ -2012,5 +2016,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazivanje preko drugih aplikacija na ekranu"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Obavještenje za informacije Rutinskog načina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Moguće je da će se baterija isprazniti prije uobičajenog punjenja"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Ušteda baterije je aktivirana da bi se produžio vijek trajanja baterije"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Učitavanje"</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 35c223b..1b1335d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Obre amb"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Obre amb %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Obre"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dona accés per obrir enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dona accés per obrir enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dona accés"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edita amb"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edita amb %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edita"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una vegada"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuració"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admet perfils professionals."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tauleta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisor"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correcció del color"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La drecera d\'accessibilitat ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La drecera d\'accessibilitat ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Torna a utilitzar la drecera d\'accessibilitat per iniciar la funció d\'accessibilitat actual"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Tria la funció que s\'utilitzarà quan toquis el botó Accessibilitat:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per canviar les funcions, toca i mantén premut el botó Accessibilitat."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliació"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Càmera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micròfon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"es mostra sobre altres aplicacions a la pantalla"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificació d\'informació del mode de rutina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"És possible que la bateria s\'esgoti abans de la càrrega habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"S\'ha activat l\'estalvi de bateria per allargar-ne la durada"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"S\'està carregant"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0061ca7..6a65be3 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otevřít v aplikaci"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otevřít v aplikaci %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otevřít"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Udělte přístup k otevírání odkazů <xliff:g id="HOST">%1$s</xliff:g> pomocí aplikace"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Udělte přístup k otevírání odkazů <xliff:g id="HOST">%1$s</xliff:g> pomocí aplikace <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udělit přístup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Upravit v aplikaci"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upravit v aplikaci %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Upravit"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Přijmout hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Pouze jednou"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavení"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s pracovní profily nepodporuje."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televize"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Oprava barev"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Zkratka přístupnosti zapnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Zkratka přístupnosti vypnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znovu použijte zkratku přístupnosti, čímž spustíte aktuální funkci pro usnadnění přístupu"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Určete, jakou funkci aktivujete klepnutím na tlačítko Přístupnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Chcete-li vybrat jinou funkci, podržte tlačítko Přístupnost."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zvětšení"</string>
@@ -2045,5 +2049,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparát"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"zobrazení přes ostatní aplikace na obrazovce"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Informační oznámení režimu sledu činností"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterie se možná vybije před obvyklým časem nabití"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Byl aktivován spořič baterie za účelem prodloužení výdrže"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Načítání"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2795efe..ae50f32 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -87,7 +87,7 @@
     <string name="NetworkPreferenceSwitchSummary" msgid="509327194863482733">"Prøv at skifte dit foretrukne netværk. Tryk for skifte."</string>
     <string name="EmergencyCallWarningTitle" msgid="813380189532491336">"Det er ikke muligt at foretage nødopkald"</string>
     <string name="EmergencyCallWarningSummary" msgid="1899692069750260619">"Det er ikke muligt at foretage nødopkald via Wi‑Fi"</string>
-    <string name="notification_channel_network_alert" msgid="4427736684338074967">"Underretninger"</string>
+    <string name="notification_channel_network_alert" msgid="4427736684338074967">"Notifikationer"</string>
     <string name="notification_channel_call_forward" msgid="2419697808481833249">"Viderestilling af opkald"</string>
     <string name="notification_channel_emergency_callback" msgid="6686166232265733921">"Nødtilbagekaldstilstand"</string>
     <string name="notification_channel_mobile_data_status" msgid="4575131690860945836">"Status for mobildata"</string>
@@ -187,7 +187,7 @@
     <string name="work_profile_deleted_description_dpm_wipe" msgid="8823792115612348820">"Din arbejdsprofil er ikke længere tilgængelig på denne enhed"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="8986903510053359694">"For mange mislykkede adgangskodeforsøg"</string>
     <string name="network_logging_notification_title" msgid="6399790108123704477">"Dette er en administreret enhed"</string>
-    <string name="network_logging_notification_text" msgid="7930089249949354026">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se oplysninger."</string>
+    <string name="network_logging_notification_text" msgid="7930089249949354026">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se info."</string>
     <string name="factory_reset_warning" msgid="5423253125642394387">"Enheden slettes"</string>
     <string name="factory_reset_message" msgid="9024647691106150160">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string>
     <string name="printing_disabled_by" msgid="8936832919072486965">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -249,7 +249,7 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Taleassistent"</string>
     <string name="global_action_lockdown" msgid="1099326950891078929">"Lukning"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_hidden_text" msgid="6351207030447943784">"Ny underretning"</string>
+    <string name="notification_hidden_text" msgid="6351207030447943784">"Ny notifikation"</string>
     <string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Virtuelt tastatur"</string>
     <string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"Fysisk tastatur"</string>
     <string name="notification_channel_security" msgid="7345516133431326347">"Sikkerhed"</string>
@@ -262,22 +262,22 @@
     <string name="notification_channel_network_available" msgid="4531717914138179517">"Tilgængeligt netværk"</string>
     <string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
     <string name="notification_channel_device_admin" msgid="1568154104368069249">"Enhedsadministration"</string>
-    <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikationer"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo til udstilling i butik"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-forbindelse"</string>
     <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Appen kører"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps, der bruger batteri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger batteri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps bruger batteri"</string>
-    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryk for at se info om batteri- og dataforbrug"</string>
     <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="8836124313744349203">"Skift til personlig profil"</string>
     <string name="managed_profile_label" msgid="8947929265267690522">"Skift til arbejdsprofil"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
-    <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine kontaktpersoner?"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontakter"</string>
+    <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine kontakter?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"få adgang til enhedens placering"</string>
     <string name="permgrouprequest_location" msgid="3788275734953323491">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til enhedens placering?"</string>
@@ -393,11 +393,11 @@
     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Tillader, at appen kan sende klæbende udsendelser, der forbliver tilbage, når udsendelsen er slut. Overdreven brug kan gøre din tablet langsom eller ustabil ved at tvinge den til at bruge for meget hukommelse."</string>
     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Giver appen lov til at sende klæbende udsendelser, som ikke forsvinder, når udsendelsen er slut. Overdreven brug kan gøre fjernsynet langsomt eller ustabilt ved at få det til at bruge for meget hukommelse."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Tillader, at appen kan sende klæbende udsendelser, der forbliver tilbage, når udsendelsen er slut. Overdreven brug kan gøre din telefon langsom eller ustabil ved at tvinge den til at bruge for meget hukommelse."</string>
-    <string name="permlab_readContacts" msgid="8348481131899886131">"læse dine kontaktpersoner"</string>
+    <string name="permlab_readContacts" msgid="8348481131899886131">"læse dine kontakter"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Tillader, at appen kan læse data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Giver appen lov til at læse data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på andre måder kommunikeret med bestemte personer. Denne tilladelse gør det muligt for apps at gemme dine kontaktoplysninger, og ondsindede apps kan dele kontaktoplysninger uden din viden."</string>
     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Tillader, at appen kan læse data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
-    <string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontaktpersoner"</string>
+    <string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontakter"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til dem, sendt dem en mail eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Giver appen lov til at ændre data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på anden måde kommunikeret med bestemte kontakter. Denne tilladelse gør det muligt for apps at slette kontaktoplysninger."</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til dem, sendt en mail til dem eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
@@ -624,10 +624,10 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
-    <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
-    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, f.eks. dem, der er sendt af andre apps."</string>
-    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til notifikationer"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde notifikationer, f.eks. dem, der er sendt af andre apps."</string>
+    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en notifikationslyttertjeneste"</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en notifikationslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"oprette binding til en tjeneste til formidling af betingelser"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til formidling af betingelser. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"fastlås til en drømmetjeneste"</string>
@@ -1098,7 +1098,7 @@
     <string name="sms" msgid="4560537514610063430">"Send besked"</string>
     <string name="sms_desc" msgid="7526588350969638809">"Send en besked til det valgte telefonnummer"</string>
     <string name="add_contact" msgid="7867066569670597203">"Tilføj"</string>
-    <string name="add_contact_desc" msgid="4830217847004590345">"Føj til kontaktpersoner"</string>
+    <string name="add_contact_desc" msgid="4830217847004590345">"Føj til kontakter"</string>
     <string name="view_calendar" msgid="979609872939597838">"Se"</string>
     <string name="view_calendar_desc" msgid="5828320291870344584">"Se det valgte tidspunkt i kalenderen"</string>
     <string name="add_calendar_event" msgid="1953664627192056206">"Planlæg"</string>
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Åbn med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åbn med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åbn"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Giv adgang til at åbne <xliff:g id="HOST">%1$s</xliff:g>-link med"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Giv adgang til at åbne <xliff:g id="HOST">%1$s</xliff:g>-links med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Giv adgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Rediger"</string>
@@ -1214,19 +1217,19 @@
     <string name="volume_call" msgid="3941680041282788711">"Lydstyrke for opkald"</string>
     <string name="volume_bluetooth_call" msgid="2002891926351151534">"Lydstyrke for Bluetooth under opkald"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Lydstyrke for alarm"</string>
-    <string name="volume_notification" msgid="2422265656744276715">"Lydstyrke for underretninger"</string>
+    <string name="volume_notification" msgid="2422265656744276715">"Lydstyrke for notifikationer"</string>
     <string name="volume_unknown" msgid="1400219669770445902">"Lydstyrke"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Lydstyrke for bluetooth"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Lydstyrke for ringetone"</string>
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Lydstyrke for opkald"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Lydstyrke for medier"</string>
-    <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for underretninger"</string>
+    <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for notifikationer"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</string>
     <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyde"</string>
-    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Underretningslyde"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notifikationslyde"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Ukendt"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Tilgængelige Wi-Fi-netværk</item>
@@ -1436,10 +1439,10 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Hjælpefunktioner"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
-    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
+    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notifikationslytter"</string>
     <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-lyttefunktion"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tjeneste til formidling af betingelser"</string>
-    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste til rangering af underretninger"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste til rangering af notifikationer"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="1610714069627824309">"Tryk for at administrere netværket."</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare opkaldet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altid"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Kun én gang"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Indstillinger"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s understøtter ikke arbejdsprofil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korriger farve"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Genvejen til hjælpefunktioner aktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Genvejen til hjælpefunktioner deaktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Brug Genvej til hjælpefunktioner for at starte den aktuelle hjælpefunktion"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Vælg, hvilken funktion du vil bruge, når du trykker på knappen Hjælpefunktioner:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryk på knappen Hjælpefunktioner, og hold fingeren nede for at skifte funktioner."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørrelse"</string>
@@ -1858,7 +1862,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
     </plurals>
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uden kategori"</string>
-    <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse underretninger er."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse notifikationer er."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
@@ -1873,7 +1877,7 @@
     <string name="app_suspended_default_message" msgid="123166680425711887">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="1131804827776778187">"Få flere oplysninger"</string>
     <string name="work_mode_off_title" msgid="1118691887588435530">"Skal arbejdsprofilen slås til?"</string>
-    <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, underretninger, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
+    <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, notifikationer, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Slå til"</string>
     <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
     <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Søg efter opdatering"</string>
@@ -1962,11 +1966,11 @@
     <string name="harmful_app_warning_title" msgid="8982527462829423432">"Der er registreret en skadelig app"</string>
     <string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7867478911006447565">"Rediger"</string>
-    <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Telefonen vil vibrere ved opkald og underretninger"</string>
-    <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Der afspilles ikke lyd ved opkald og underretninger"</string>
+    <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Telefonen vil vibrere ved opkald og notifikationer"</string>
+    <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Der afspilles ikke lyd ved opkald og notifikationer"</string>
     <string name="notification_channel_system_changes" msgid="5072715579030948646">"Systemændringer"</string>
     <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Forstyr ikke"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Nyhed! Forstyr ikke skjuler underretninger"</string>
+    <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Nyhed! Forstyr ikke skjuler notifikationer"</string>
     <string name="zen_upgrade_notification_visd_content" msgid="5533674060311631165">"Tryk for at få flere oplysninger og foretage ændringer."</string>
     <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Tilstanden Forstyr ikke blev ændret"</string>
     <string name="zen_upgrade_notification_content" msgid="1794994264692424562">"Tryk for at se, hvad der er blokeret."</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"vises over andre apps på din skærm"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifikation med oplysninger om rutinetilstand"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Enheden løber muligvis tør for batteri, inden du normalt oplader den"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Indlæser"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6087438..895eaa1 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Öffnen mit"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mit %1$s öffnen"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öffnen"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Zugriff zum Öffnen von <xliff:g id="HOST">%1$s</xliff:g>-Links erlauben"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Zugriff zum Öffnen von <xliff:g id="HOST">%1$s</xliff:g>-Links mit <xliff:g id="APPLICATION">%2$s</xliff:g> erlauben"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Zugriff erlauben"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bearbeiten mit"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Mit %1$s bearbeiten"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Bearbeiten"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Anruf annehmen?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Immer"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Nur diesmal"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Einstellungen"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Das Arbeitsprofil wird von %1$s nicht unterstützt."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Farbkorrektur"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung aktiviert"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Verwende noch einmal die Verknüpfung für Bedienungshilfen, um die aktuelle Bedienungshilfe zu starten."</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wähle eine Funktion aus, die verwendet wird, wenn du auf die Schaltfläche für die Bedienungshilfen tippst:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Um die Funktionen zu ändern, halte die Schaltfläche für die Bedienungshilfen gedrückt."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergrößerung"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wird über anderen Apps auf dem Bildschirm angezeigt"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Infomitteilung zum Ablaufmodus"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Dein Akku könnte vor der gewöhnlichen Ladezeit leer sein"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Energiesparmodus aktiviert, um die Akkulaufzeit zu verlängern"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Wird geladen"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index f899309..441435b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Άνοιγμα με"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Άνοιγμα με %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Άνοιγμα"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Παραχώρηση πρόσβασης για το άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Παραχώρηση πρόσβασης για το άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Παροχή πρόσβασης"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Επεξεργασία με"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Επεξεργασία με %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Επεξεργασία"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Αποδοχή κλήσης;"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Πάντα"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Μόνο μία φορά"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ρυθμίσεις"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Το προφίλ εργασίας δεν υποστηρίζεται από %1$s"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Τηλεόραση"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Διόρθωση χρωμάτων"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Η συντόμευση προσβασιμότητας ενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Η συντόμευση προσβασιμότητας απενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Χρησιμοποιήστε τη Συντόμευση προσβασιμότητας ξανά, για να ξεκινήσετε την τρέχουσα λειτουργία προσβασιμότητας"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Επιλέξτε μια λειτουργία που θα χρησιμοποιείται κατά το πάτημα του κουμπιού \"Προσβασιμότητα\"."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Για να αλλάξετε λειτουργίες, αγγίξτε παρατεταμένα το κουμπί \"Προσβασιμότητα\"."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Μεγιστοποίηση"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Κάμερα"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Μικρόφωνο"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"εμφανίζεται πάνω σε άλλες εφαρμογές στην οθόνη σας"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ειδοποίηση πληροφοριών λειτουργίας Ρουτίνας"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Η μπαταρία μπορεί να εξαντληθεί πριν από τη συνηθισμένη φόρτιση"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε για την επέκταση της διάρκειας ζωής της μπαταρίας"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Φόρτωση"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 7288a80..8b49cf1 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 0481755..888bc26 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7288a80..8b49cf1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7288a80..8b49cf1 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5d3b466..b4f1156d0 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1126,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‎Open with‎‏‎‎‏‎"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎Open with %1$s‎‏‎‎‏‎"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‎Open‎‏‎‎‏‎"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎Give access to open ‎‏‎‎‏‏‎<xliff:g id="HOST">%1$s</xliff:g>‎‏‎‎‏‏‏‎ links with‎‏‎‎‏‎"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‎Give access to open ‎‏‎‎‏‏‎<xliff:g id="HOST">%1$s</xliff:g>‎‏‎‎‏‏‏‎ links with ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎Give access‎‏‎‎‏‎"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‎Edit with‎‏‎‎‏‎"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎Edit with %1$s‎‏‎‎‏‎"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎Edit‎‏‎‎‏‎"</string>
@@ -1564,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎Accept call?‎‏‎‎‏‎"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎Always‎‏‎‎‏‎"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎Just once‎‏‎‎‏‎"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎Settings‎‏‎‎‏‎"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎%1$s doesn\'t support work profile‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎Tablet‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎TV‎‏‎‎‏‎"</string>
@@ -1643,7 +1647,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎Color Correction‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎Accessibility Shortcut turned ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ on‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‎‏‎Accessibility Shortcut turned ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ off‎‏‎‎‏‎"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎Use Accessibility Shortcut again to start the current accessibility feature‎‏‎‎‏‎"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‎Press and hold both volume keys for three seconds to use ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎Choose a feature to use when you tap the Accessibility button:‎‏‎‎‏‎"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎To change features, touch &amp; hold the Accessibility button.‎‏‎‎‏‎"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎Magnification‎‏‎‎‏‎"</string>
@@ -1973,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎Camera‎‏‎‎‏‎"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎Microphone‎‏‎‎‏‎"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‏‎displaying over other apps on your screen‎‏‎‎‏‎"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎Routine Mode info notification‎‏‎‎‏‎"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‏‏‎Battery may run out before usual charge‎‏‎‎‏‎"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎Battery Saver activated to extend battery life‎‏‎‎‏‎"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎Loading‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d369da5..e821fca 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Otorgar acceso para abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Otorgar acceso para abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Otorgar acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo de accesibilidad activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo de accesibilidad desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Vuelve a usar el acceso directo de accesibilidad para iniciar la función de accesibilidad actual"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Elige una función para usar cuando presionas el botón Accesibilidad:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar funciones, mantén presionado el botón Accesibilidad."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se superpone a otras apps en tu pantalla"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificación de información del modo de Rutinas"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Es posible que la batería se agote antes de la carga habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Se activó el Ahorro de batería para extender la duración de la batería"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9174248..3f93565 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Permitir acceso para abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Permitir acceso para abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permitir acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Cambiar"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ajustes"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo a accesibilidad ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo a accesibilidad ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa de nuevo la combinación de teclas de accesibilidad para iniciar la función de accesibilidad actual"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Selecciona la función que se utilizará cuando toques el botón Accesibilidad:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar las funciones, mantén pulsado el botón Accesibilidad."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliar"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se muestra sobre otras aplicaciones que haya en la pantalla"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificación sobre el modo rutina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Es posible que te quedes sin batería antes de lo habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Se ha activado el ahorro de batería para aumentar la duración de la batería"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index f20b35f..466ead0 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Avamine:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avamine rakendusega %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ava"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Juurdepääsu andmine, et avada üksuse <xliff:g id="HOST">%1$s</xliff:g> lingid"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Juurdepääsu andmine, et avada üksuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Juudep. andmine"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Muutmine:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muutmine rakendusega %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Muuda"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alati"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Ainult üks kord"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Seaded"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei toeta tööprofiili"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tahvelarvuti"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Teler"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Värviparandus"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisse"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> välja"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Praeguse juurdepääsufunktsiooni käivitamiseks kasutage juurdpääsetavuse otseteed uuesti"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valige, millist funktsiooni kasutada, kui vajutate nuppu Juurdepääsetavus:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funktsioonide muutmiseks puudutage pikalt nuppu Juurdepääsetavus."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurendus"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kaamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"teie ekraanil muude rakenduste peal kuvamine"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Laadimine"</string>
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 153eeae..c478bab 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ireki"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Eman <xliff:g id="HOST">%1$s</xliff:g> estekak irekitzeko baimena aplikazio honi:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Eman <xliff:g id="APPLICATION">%2$s</xliff:g> aplikazioari <xliff:g id="HOST">%1$s</xliff:g> irekitzeko baimena"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Eman sarbidea"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editatu honekin:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editatu"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Deia onartu nahi duzu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Beti"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Behin soilik"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ezarpenak"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s abiarazleak ez du laneko profil hau onartzen"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tableta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telebista"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Koloreen zuzenketa"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu du"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu du"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Uneko erabilerraztasun-eginbidea abiarazteko, erabili erabilerraztasun-lasterbidea berriro"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bolumen-tekla biak hiru segundoz"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Aukeratu zein eginbide erabili nahi duzun Erabilerraztasuna botoia sakatzean:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Eginbideak aldatzeko, eduki sakatuta Erabilerraztasuna botoia."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Lupa"</string>
@@ -1976,5 +1980,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofonoa"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"pantailako beste aplikazioen gainean bistaratzen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ohitura moduaren informazio-jakinarazpena"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baliteke bateria ohi baino lehenago agortzea"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Kargatzen"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 76845c8..c38f1d2 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"باز کردن با"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏باز کردن با %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"باز کردن"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ارائه دسترسی برای باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ارائه دسترسی برای باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ارائه دسترسی"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ویرایش با"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ویرایش با %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ویرایش"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"تماس را می‌پذیرید؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"همیشه"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"فقط این بار"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"تنظیمات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s از نمایه کاری پشتیبانی نمی‌کند"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"رایانهٔ لوحی"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"تلویزیون"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"تصحیح رنگ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"«میان‌بر دسترس‌پذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را روشن کرد"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"«میان‌بر دسترس‌پذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را خاموش کرد"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"برای راه‌اندازی ویژگی دسترس‌پذیری کنونی، دوباره از «میان‌بر دسترس‌پذیری» استفاده کنید"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"قابلیتی را انتخاب کنید که هنگام ضربه زدن روی دکمه «دسترس‌پذیری» استفاده می‌شود:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"برای تغییر دادن قابلیت‌ها، دکمه «دسترس‌پذیری» را لمس کنید و نگه‌دارید."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"درشت‌نمایی"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"دوربین"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"میکروفون"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"نمایش روی برنامه‌های دیگر در صفحه‌نمایش"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"درحال بارگیری"</string>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 16c96cc..ac6d8dc 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Avaa sovelluksessa"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avaa sovelluksessa %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Avaa"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Salli linkkien (<xliff:g id="HOST">%1$s</xliff:g>) avaaminen:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Salli linkkien (<xliff:g id="HOST">%1$s</xliff:g>) avaaminen: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Salli"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Muokkaa sovelluksessa"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muokkaa sovelluksessa %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Muokkaa"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vastataanko puheluun?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Aina"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Vain kerran"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Asetukset"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei tue työprofiilia"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletti"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisio"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Värinkorjaus"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> otettiin käyttöön esteettömyystilan pikanäppäimellä."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> poistettiin käytöstä esteettömyystilan pikanäppäimellä."</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Valitse esteettömyystilan oikopolku uudelleen käynnistääksesi esteettömyysominaisuuden"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valitse toiminto, jonka Esteettömyys-painike aktivoi:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jos haluat muokata ominaisuuksia, kosketa Esteettömyys-painiketta pitkään."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurennus"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"näkyy näytöllä muiden sovellusten päällä"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Ladataan"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6fb1f12..8383078 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Accorder l\'accès pour ouvrir les liens de <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Accorder l\'accès pour ouvrir les liens de <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifier"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne prend pas en charge le profil professionnel"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablette"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Télévision"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous touchez le bouton d\'accessibilité :"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, maintenez le doigt sur le bouton d\'accessibilité."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zoom"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Appareil photo"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"superpose du contenu par-dessus d\'autres applications à l\'écran"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Chargement en cours…"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index fa8c7f0..3e87d88 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Autoriser l\'ouverture des liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Autoriser l\'ouverture des liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifier"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s n\'est pas compatible avec le profil professionnel."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablette"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Téléviseur"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous appuyez sur le bouton d\'accessibilité :"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, appuyez de manière prolongée sur le bouton d\'accessibilité."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Agrandissement"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Caméra"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micro"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se superpose aux autres applications sur l\'écran"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notification d\'information du mode Routine"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Vous risquez d\'être à court de batterie plus tôt que prévu"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Économiseur de batterie activé pour prolonger l\'autonomie"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Chargement…"</string>
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2c9b09d..1e78401 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -32,7 +32,7 @@
     <string name="unknownName" msgid="6867811765370350269">"Descoñecido"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correo de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
-    <string name="mmiError" msgid="5154499457739052907">"Problema de conexión ou código MMI non válido."</string>
+    <string name="mmiError" msgid="5154499457739052907">"Problema de conexión ou código MMI non-válido."</string>
     <string name="mmiFdnError" msgid="5224398216385316471">"A operación está restrinxida a números de marcación fixa."</string>
     <string name="mmiErrorWhileRoaming" msgid="762488890299284230">"Non se pode cambiar a configuración do desvío de chamadas desde o teléfono mentres estás en itinerancia."</string>
     <string name="serviceEnabled" msgid="8147278346414714315">"Activouse o servizo."</string>
@@ -150,7 +150,7 @@
     <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non desviada"</string>
     <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non reenviada"</string>
     <string name="fcComplete" msgid="3118848230966886575">"Código de función completo"</string>
-    <string name="fcError" msgid="3327560126588500777">"Problema de conexión ou código de función non válido"</string>
+    <string name="fcError" msgid="3327560126588500777">"Problema de conexión ou código de función non-válido"</string>
     <string name="httpErrorOk" msgid="1191919378083472204">"Aceptar"</string>
     <string name="httpError" msgid="7956392511146698522">"Produciuse un erro na rede."</string>
     <string name="httpErrorLookup" msgid="4711687456111963163">"Non se puido atopar o URL."</string>
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acceso para abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acceso para abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceptar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só unha vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non admite o perfil de traballo"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tableta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisión"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atallo de accesibilidade activou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atallo de accesibilidade desactivou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Para iniciar a función de accesibilidade actual, utiliza de novo o atallo de accesibilidade"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolle que función queres utilizar cando toques o botón Accesibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar as funcións, mantén premido o botón Accesibilidade."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"mostrando outras aplicacións na pantalla"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index da8a6e5..958183d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"આની સાથે ખોલો"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s સાથે ખોલો"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ખોલો"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"આના વડે <xliff:g id="HOST">%1$s</xliff:g>ની લિંક ખોલવા માટે ઍક્સેસ આપો"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> વડે <xliff:g id="HOST">%1$s</xliff:g>ની લિંક ખોલવા માટે ઍક્સેસ આપો"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ઍક્સેસ આપો"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"આનાથી સંપાદિત કરો"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s સાથે સંપાદિત કરો"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"સંપાદિત કરો"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"કૉલ સ્વીકારીએ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"હંમેશા"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ફક્ત એક વાર"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"સેટિંગ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s કાર્ય પ્રોફાઇલનું સમર્થન કરતું નથી"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ટેબ્લેટ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"રંગ સુધારણા"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"વર્તમાન ઍક્સેસિબિલિટી સુવિધાને શરૂ કરવા માટે ફરીથી ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરો"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"જ્યારે તમે ઍક્સેસિબિલિટી બટન પર ટૅપ કરો, ત્યારે ઉપયોગ કરવાની સુવિધા પસંદ કરો:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"સુવિધાઓ બદલવા માટે, ઍક્સેસિબિલિટી બટન દબાવી રાખો."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"વિસ્તૃતીકરણ"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"કૅમેરા"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"માઇક્રોફોન"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"આ તમારી સ્ક્રીન પર અન્ય ઍપની ઉપર દેખાશે"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"લોડિંગ"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4349c09..6a247af 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"इसमें खोलें"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s में खोलें"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोलें"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"इससे <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलने का एक्सेस दें"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> से <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलने का एक्सेस दें"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"एक्सेस दें"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"इसके ज़रिये बदलाव करें"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s की मदद से बदलाव करें"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"बदलाव करें"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकार करें?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"हमेशा"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"केवल एक बार"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफ़ाइल का समर्थन नहीं करता"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"टैबलेट"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीवी"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"रंग में सुधार करने की सुविधा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू किया"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद किया"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"मौजूदा सुलभता सुविधा शुरू करने के लिए \'सुलभता शॉर्टकट\' का फिर से इस्तेमाल करें"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"सुलभता बटन पर टैप करते समय इस्तेमाल की जाने वाली सुविधा चुनें:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाओं में बदलाव करने के लिए, सुलभता बटन को दबाकर रखें."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"बड़ा करना"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"कैमरा"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"माइक्रोफ़ोन"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"आपकी स्क्रीन पर, इस्तेमाल हो रहे दूसरे ऐप्लिकेशन के ऊपर दिखाया जा रहा है"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"प्राेफ़ाइल लोड हो रही है"</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2747521..92fdbba 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1148,6 +1148,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvaranje pomoću aplikacije"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvaranje pomoću aplikacije %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Omogućite pristup za otvaranje <xliff:g id="HOST">%1$s</xliff:g> veza pomoću aplikacije"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Omogućite pristup za otvaranje <xliff:g id="HOST">%1$s</xliff:g> veza pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogući pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Uređivanje pomoću aplikacije"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uređivanje pomoću aplikacije %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Uredi"</string>
@@ -1589,6 +1592,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava radni profil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletno računalo"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
@@ -1669,7 +1673,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boje"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečac pristupačnosti uključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečac pristupačnosti isključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo upotrijebite prečac pristupačnosti da biste pokrenuli trenutačnu značajku pristupačnosti"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite značajku koju ćete upotrebljavati kada dodirnete gumb Pristupačnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da biste promijenili značajke, dodirnite i zadržite gumb Pristupačnost."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povećavanje"</string>
@@ -2010,5 +2014,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparat"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazuje se preko drugih aplikacija na zaslonu"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Učitavanje"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 10538f4..c04d4fe 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Megnyitás a következővel:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Megnyitás a következővel: %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Megnyitás"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Engedély megadása, hogy a(z) <xliff:g id="HOST">%1$s</xliff:g> linkek a következő alkalmazásban nyíljanak meg:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Engedély megadása, hogy a(z) <xliff:g id="HOST">%1$s</xliff:g> linkek a következő alkalmazásban nyíljanak meg: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Engedély adása"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Szerkesztés a következővel:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Szerkesztés a következővel: %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Szerkesztés"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Fogadja a hívást?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Mindig"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Csak egyszer"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Beállítások"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"A(z) %1$s nem támogatja a munkaprofilokat."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Táblagép"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Színkorrekció"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"A Kisegítő lehetőségek gyorsparancsa bekapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"A Kisegítő lehetőségek gyorsparancsa kikapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Használja újból a Kisegítő lehetőségek gyorsparancsát az aktuális kisegítő lehetőségek elindításához"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Válassza ki a Kisegítő lehetőségek gombra koppintáskor használni kívánt funkciót:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"A funkciók módosításához tartsa lenyomva a Kisegítő lehetőségek gombot."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Nagyítás"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"megjelenítés a képernyőn lévő egyéb alkalmazások előtt"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Betöltés"</string>
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index fbb5f4b..84280ac 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Բացել հետևյալ ծրագրով՝"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Բացել ծրագրով՝ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Բացել"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթը հղումները բացվեն հետևյալ հավելվածում՝"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթի հղումները բացվեն <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածում"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Թույլատրել"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Խմբագրել հետևյալ ծրագրով՝"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Խմբագրել հետևյալով՝ %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Փոփոխել"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ընդունե՞լ զանգը:"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Միշտ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Միայն մեկ անգամ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Կարգավորումներ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s-ը չի աջակցում աշխատանքային պրոֆիլներ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Գրասալիկ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Հեռուստացույց"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Գունաշտկում"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Մատչելիության դյուրանցումն միացրել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Մատչելիության դյուրանցումն անջատել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Հատուկ գործառույթների դյուրանցումը գործարկելու համար նորից օգտագործեք համապատասխան դյուրանցումը"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Ընտրեք որևէ գործառույթ, որը կօգտագործվի Հատուկ գործառույթներ կոճակին հպելու դեպքում՝"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Գործառույթները փոխելու համար հպեք և պահեք Հատուկ գործառույթներ կոճակը։"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Խոշորացում"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Տեսախցիկ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Խոսափող"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ցուցադրվում է մյուս հավելվածների վերևում"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Բեռնում"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3c6e347..905d3f2 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Berikan akses untuk membuka link <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Berikan akses untuk membuka link <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Selalu"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setelan"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak mendukung profil kerja"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Koreksi Warna"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan Aksesibilitas mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Aksesibilitas menonaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Aksesibilitas lagi untuk memulai fitur aksesibilitas saat ini"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih fitur yang akan digunakan saat menge-tap tombol Aksesibilitas:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk mengubah fitur, sentuh &amp; tahan tombol Aksesibilitas."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ditampilkan di atas aplikasi lain di layar"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifikasi info Mode Rutinitas"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterai mungkin habis sebelum pengisian daya biasanya"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Penghemat Baterai diaktifkan untuk memperpanjang masa pakai baterai"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Memuat"</string>
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index f638ff8..432fc7e 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Opna með"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Opna með %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Opna"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Veita aðgang til að opna <xliff:g id="HOST">%1$s</xliff:g> tengla með"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Veita aðgang til að opna <xliff:g id="HOST">%1$s</xliff:g> tengla með <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Veita aðgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Breyta með"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Breyta með %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Breyta"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Samþykkja símtal?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltaf"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara einu sinni"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Stillingar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s styður ekki vinnusnið"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Spjaldtölva"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Sjónvarp"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Litaleiðrétting"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Flýtileið aðgengisstillingar kveikti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Flýtileið aðgengisstillingar slökkti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Notaðu flýtileið aðgengisstillingar aftur til að opna aðgengiseiginleika"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Veldu eiginleika sem á að nota þegar ýtt er á aðgengishnappinn:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Haltu fingri á aðgengishnappinum til að breyta eiginleikum."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Stækkun"</string>
@@ -1976,5 +1980,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Myndavél"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Hljóðnemi"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"birt yfir öðrum forritum á skjánum"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Upplýsingatilkynning aðgerðastillingar"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Rafhlaðan kann að tæmast áður en hún kemst í hleðslu"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Kveikt á rafhlöðusparnaði til að lengja endingu rafhlöðunnar"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Hleður"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index c9c8f0c..d76049d 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Apri con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Apri con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Apri"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dai l\'accesso per aprire i link di <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dai l\'accesso per aprire i link di <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Fornisci accesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifica con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifica con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifica"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accettare la chiamata?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una volta"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Impostazioni"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non supporta il profilo di lavoro"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correzione del colore"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La scorciatoia Accessibilità ha attivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La scorciatoia Accessibilità ha disattivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa di nuovo la scorciatoia Accessibilità per avviare l\'attuale funzione di accessibilità"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Scegli una funzione da usare quando tocchi il pulsante Accessibilità:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per cambiare le funzioni, tocca e tieni premuto il pulsante Accessibilità."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ingrandimento"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotocamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"si sovrappone ad altre app sullo schermo"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifica di informazioni sulla modalità Routine"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"La batteria potrebbe esaurirsi prima della ricarica abituale"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Risparmio energetico attivo per far durare di più la batteria"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Caricamento"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 26f6988f..df9631e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"פתח באמצעות"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏פתח באמצעות %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"פתח"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"הענקת גישה לפתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"הענקת גישה לפתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"הענקת גישה"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ערוך באמצעות"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ערוך באמצעות %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"עריכה"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"האם לקבל את השיחה?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"תמיד"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"רק פעם אחת"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"הגדרות"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s אינו תומך בפרופיל עבודה"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"טאבלט"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"טלוויזיה"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"תיקון צבעים"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל על-ידי קיצור הדרך לנגישות"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת על-ידי קיצור הדרך לנגישות"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"יש להשתמש שוב במקש הקיצור לנגישות כדי להפעיל את תכונת הנגישות הנוכחית"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"בחר תכונה שתופעל כשתלחץ על הלחצן \'נגישות\':"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"כדי להחליף תכונה, גע בלחצן \'נגישות\' והחזק אותו."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"הגדלה"</string>
@@ -2045,5 +2049,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"מצלמה"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"מיקרופון"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"תצוגה מעל אפליקציות אחרות במסך"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"בטעינה"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 45587cb..991ef13 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"アプリで開く"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sで開く"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開く"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> のリンクを開くには、アクセス権を付与してください"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> で <xliff:g id="HOST">%1$s</xliff:g> のリンクを開くには、アクセス権を付与してください"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"アクセス権を付与"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"編集に使用"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sで編集"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"編集"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"通話を受けますか?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"常時"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"1回のみ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sは仕事用プロファイルをサポートしていません"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"タブレット"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"テレビ"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色補正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は ON になっています"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は OFF になっています"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"現在のユーザー補助機能を開始するには、ユーザー補助機能のショートカットをもう一度使用してください"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"[ユーザー補助] ボタンをタップした場合に使用する機能を選択してください。"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"機能を変更するには、[ユーザー補助] ボタンを押し続けてください。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"拡大"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"カメラ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"マイク"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"画面の他のアプリの上に重ねて表示"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"読み込んでいます"</string>
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 07df9fc..cfce254 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"გახსნა აპით"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s-ით გახსნა"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"გახსნა"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების შემდეგი აპით გახსნის წვდომის მინიჭება:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების <xliff:g id="APPLICATION">%2$s</xliff:g>-ით გახსნის წვდომის მინიჭება"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"წვდომის მინიჭება"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"რედაქტირება აპით:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"რედაქტირება %1$s-ით"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"რედაქტირება"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"უპასუხებთ ზარს?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ყოველთვის"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"მხოლოდ ერთხელ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"პარამეტრები"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s მხარს არ უჭერს სამუშაო პროფილს"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ტაბლეტი"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ტელევიზია"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ფერთა კორექცია"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"მარტივი წვდომის მალსახმობმა ჩართო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"მარტივი წვდომის მალსახმობმა გამორთო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"მარტივი წვდომის ამჟამინდელი ფუნქციის გასაშვებად გამოიყენეთ მარტივი წვდომის მალსახმობი"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"აირჩიეთ მარტივი წვდომის ღილაკზე შეხებისას გამოსაყენებელი ფუნქცია:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ფუნქციების შესაცვლელად ხანგრძლივად შეეხეთ მარტივი წვდომის ღილაკს."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"გადიდება"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"კამერა"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"მიკროფონი"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"სხვა აპების გადაფარვით ჩანს თქვენს ეკრანზე"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"იტვირთება"</string>
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index c622094..fb70fa9 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Басқаша ашу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s қолданбасымен ашу"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ашу"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін келесі қолданбамен ашу үшін рұқсат беру:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасымен ашу үшін рұқсат беру"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Рұқсат беру"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Келесімен өңдеу"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s көмегімен өңдеу"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Өңдеу"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Қоңырауды қабылдау?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Үнемі"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Бір рет қана"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Параметрлер"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жұмыс профилін қолдамайды"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТД"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Түсті түзету"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін қосты"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін өшірді"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Арнайы мүмкіндіктер функциясын іске қосу үшін оның таңбашасын пайдаланыңыз"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"\"Арнайы мүмкіндіктер\" түймесін түрткенде пайдаланатын мүмкіндікті таңдаңыз:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Мүмкіндіктерді өзгерту үшін \"Арнайы мүмкіндіктер\" түймесін түртіп, ұстап тұрыңыз."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ұлғайту"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"экранда басқа қолданбалардың үстінен көрсету"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Жүктелуде"</string>
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ccc243d..9cc64ab 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1130,6 +1130,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"បើក​ជា​មួយ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"បើក​ជាមួយ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"បើក"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ផ្ដល់​សិទ្ធិ​ចូលប្រើ ដើម្បី​បើកតំណ <xliff:g id="HOST">%1$s</xliff:g> តាមរយៈ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ផ្ដល់​សិទ្ធិ​ចូល​ប្រើ ដើម្បី​បើកតំណ <xliff:g id="HOST">%1$s</xliff:g> តាមរយៈ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ផ្តល់​សិទ្ធិ​ចូល​ប្រើ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"កែសម្រួល​ជាមួយ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"កែសម្រួល​ជាមួយ​ %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"កែសម្រួល"</string>
@@ -1568,6 +1571,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ទទួល​ការ​ហៅ​?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ជា​និច្ច"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"តែ​ម្ដង"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ការកំណត់"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s មិន​គាំទ្រ​ប្រវត្តិរូប​ការងារ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"កុំព្យូទ័រ​បន្ទះ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ទូរទស្សន៍"</string>
@@ -1647,7 +1651,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ការ​កែ​ពណ៌"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ផ្លូវកាត់​ភាព​ងាយ​ស្រួល​បាន​បើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ផ្លូវកាត់​ភាព​ងាយ​ស្រួល​បាន​បិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ប្រើផ្លូវកាត់​ភាពងាយស្រួល​ម្ដងទៀត ដើម្បី​ចាប់ផ្ដើម​មុខងារ​ភាពងាយប្រើ​បច្ចុប្បន្ន"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"ចុចគ្រាប់ចុច​កម្រិត​សំឡេងទាំងពីរ​ឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ជ្រើសរើស​មុខងារ​ដែលត្រូវ​ប្រើ នៅពេល​ដែល​អ្នកចុច​ប៊ូតុង​ភាពងាយស្រួល៖"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ដើម្បី​ផ្លាស់ប្តូរ​មុខងារ សូម​ចុច​ប៊ូតុង​ភាព​ងាយស្រួល​ឲ្យ​ជាប់។"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ការ​ពង្រីក"</string>
@@ -1977,5 +1981,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"កាមេរ៉ា"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"មីក្រូហ្វូន"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"កំពុងបង្ហាញ​ពីលើកម្មវិធីផ្សេងទៀត​នៅលើអេក្រង់​របស់អ្នក"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"កំពុងផ្ទុក"</string>
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 835070a..d6cde26 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ಜೊತೆಗೆ ತೆರೆಯಿರಿ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ತೆರೆ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಲು ಪ್ರವೇಶವನ್ನು ನೀಡಿ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಲು ಪ್ರವೇಶವನ್ನು ನೀಡಿ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ಪ್ರವೇಶ ಅನುಮತಿಸಿ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ಇವರ ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ಎಡಿಟ್"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ಕರೆ ಸ್ವೀಕರಿಸುವುದೇ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ಯಾವಾಗಲೂ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ಒಮ್ಮೆ ಮಾತ್ರ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ಟ್ಯಾಬ್ಲೆಟ್‌‌"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ಟಿವಿ"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಿದೆ"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಫ್ ಮಾಡಿದೆ"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ಪ್ರಸ್ತುತ ಪ್ರವೇಶದ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಪ್ರಾರಂಭಿಸಲು ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃ ಬಳಸಿ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್‌ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ನೀವು ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಟ್ಯಾಪ್ ಮಾಡಿದಾಗ ಬಳಸುವುದಕ್ಕಾಗಿ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಆರಿಸಿ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಬದಲಾಯಿಸಲು, ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಒತ್ತಿಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ಹಿಗ್ಗಿಸುವಿಕೆ"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ಕ್ಯಾಮರಾ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ಮೈಕ್ರೋಫೋನ್‌"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಮೂಲಕ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8886815..05ab555 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"연결 프로그램"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s(으)로 열기"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"열기"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"다음으로 <xliff:g id="HOST">%1$s</xliff:g> 링크를 열려면 액세스 권한 부여"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>(으)로 <xliff:g id="HOST">%1$s</xliff:g> 링크를 열려면 액세스 권한 부여"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"권한 부여"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"편집 프로그램:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s(으)로 수정"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"수정"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"통화를 수락하시겠습니까?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"항상"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"한 번만"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"설정"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s에서 직장 프로필을 지원하지 않습니다."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"태블릿"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"색상 보정"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"현재 접근성 기능을 시작하려면 접근성 단축키를 다시 사용하세요"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"접근성 버튼을 탭할 때 사용할 기능을 선택하세요."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"기능을 변경하려면 접근성 버튼을 길게 터치하세요."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"확대"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"카메라"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"마이크"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"화면에서 다른 앱 위에 표시"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"로드 중"</string>
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index de49741..88f0ef2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Төмөнкү менен ачуу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s менен ачуу"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ачуу"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Төмөнкү колдонмо менен <xliff:g id="HOST">%1$s</xliff:g> шилтемелерин  ачууга уруксат берүү"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосу менен <xliff:g id="HOST">%1$s</xliff:g> шилтемелерин  ачууга уруксат берүү"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Мүмкүнчүлүк берүү"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Төмөнкү менен түзөтүү"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s менен түзөтүү"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Түзөтүү"</string>
@@ -1568,6 +1571,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Чалуу кабыл алынсынбы?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Дайыма"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Бир жолу гана"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Жөндөөлөр"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жумуш профилин колдоого албайт"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Сыналгы"</string>
@@ -1647,7 +1651,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Түсүн тууралоо"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын күйгүздү"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын өчүрдү"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Учурдагы атайын мүмкүнчүлүктөр функциясын иштетүү үчүн кыска жолду кайра колдонуңуз"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Атайын мүмкүнчүлүктөр баскычын таптаганыңызда иштетиле турган функцияны тандаңыз:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Функцияларды өзгөртүү үчүн Атайын мүмкүнчүлүктөр баскычын басып, кармап туруңуз."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Чоңойтуу"</string>
@@ -1977,5 +1981,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"экрандагы башка терезелердин үстүнөн көрсөтүлүүдө"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Жүктөлүүдө"</string>
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9356302..7a5ab96 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ເປີດໂດຍໃຊ້"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"ເປີດ​ໂດຍ​ໃຊ້ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ເປີດ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ໃຫ້ສິດອະນຸຍາດເພື່ອເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ດ້ວຍ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ໃຫ້ສິດອະນຸຍາດເພື່ອເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ດ້ວຍ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ໃຫ້ສິດອະນຸຍາດ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"​ແກ້​ໄຂ​ໃນ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ແກ້​ໄຂ​ໃນ %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ແກ້ໄຂ"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ຮັບການໂທບໍ່?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ທຸກຄັ້ງ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ຄັ້ງດຽວ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ການຕັ້ງຄ່າ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ບໍ່​ຮອງ​ຮັບ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ແທັບເລັດ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ໂທລະພາບ"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ການແກ້ໄຂຄ່າສີ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງອີກເທື່ອໜຶ່ງເພື່ອຊອກຫາຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງໃນປັດຈຸບັນ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ເລືອກຄຸນສົມບັດທີ່ຈະໃຊ້ເມື່ອທ່ານແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ເພື່ອປ່ຽນຄຸນສົມບັດ, ໃຫ້ແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງຄ້າງໄວ້."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ການຂະຫຍາຍ"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ກ້ອງ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ໄມໂຄຣໂຟນ"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ສະແດງຜົນບັງແອັບອື່ນຢູ່ໜ້າຈໍຂອງທ່ານ"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"ກຳລັງໂຫລດ"</string>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8870ebb..90ed406 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Atidaryti naudojant"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atidaryti naudojant %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atidaryti"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Suteikite prieigą atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Suteikite prieigą atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant „<xliff:g id="APPLICATION">%2$s</xliff:g>“"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Suteikti prieigą"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redaguoti naudojant"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redaguoti naudojant %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redaguoti"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tik kartą"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nustatymai"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nepalaiko darbo profilio"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planšetinis kompiuteris"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Spalvų taisymas"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo įjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo išjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Norėdami įjungti dabartinę pritaikymo neįgaliesiems funkciją, dar kartą naudokite spartųjį pritaikymo neįgaliesiems klavišą"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pasirinkite funkciją, kuri bus naudojama, kai paliesite pritaikymo neįgaliesiems mygtuką:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jei norite pakeisti funkcijas, palieskite ir palaikykite pritaikymo neįgaliesiems mygtuką."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Didinimas"</string>
@@ -2045,5 +2049,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparatas"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofonas"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"rodo virš kitų programų jūsų ekrane"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Įkeliama"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5a1432b..e58b462 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1148,6 +1148,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Atvērt, izmantojot"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atvērt, izmantojot %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atvērt"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Piekļuves piešķiršana, lai atvērtu <xliff:g id="HOST">%1$s</xliff:g> saites lietojumprogrammā"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Piekļuves piešķiršana, lai atvērtu <xliff:g id="HOST">%1$s</xliff:g> saites lietojumprogrammā <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Atļaut piekļuvi"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediģēt, izmantojot"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediģēt, izmantojot %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Rediģēt"</string>
@@ -1589,6 +1592,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tikai vienreiz"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Iestatījumi"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Programma %1$s neatbalsta darba profilus"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planšetdators"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1673,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Krāsu korekcija"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pieejamības saīsne aktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pieejamības saīsne deaktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Lai sāktu izmantot pašreizējo pieejamības funkciju, vēlreiz izmantojiet pieejamības saīsni."</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma taustiņus un turiet tos trīs sekundes."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izvēlieties funkciju, ko izmantot, kad pieskaraties pogai Pieejamība."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Lai mainītu funkcijas, pieskarieties pogai Pieejamība un turiet to."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Palielinājums"</string>
@@ -2010,5 +2014,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofons"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"rāda pāri citām lietotnēm jūsu ekrānā"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Ielāde"</string>
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 769ac43..8bede29 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отвори со"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отвори со %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дајте пристап да се отвораат линкови на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дајте пристап да се отвораат линкови на <xliff:g id="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи пристап"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Измени со"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измени со %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Измени"</string>
@@ -1569,6 +1572,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прифати повик?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Секогаш"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само еднаш"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Поставки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддржува работен профил"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1648,7 +1652,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција на бои"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Кратенката за пристапност ја вклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Кратенката за пристапност ја исклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Повторно употребете ја кратенката за пристапност за да ја стартувате тековната функција за пристапност"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функција за користење кога ќе го допрете копчето за „Пристапност“."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За променување функции, допрете го и задржете го копчето за „Пристапност“."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Зголемување"</string>
@@ -1978,5 +1982,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"се прикажува преку други апликации на вашиот екран"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Известување за информации за режимот за рутини"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батеријата може да се потроши пред вообичаеното време за полнење"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Активиран е „Штедачот на батерија“ за да се продолжи траењето на батеријата"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Се вчитува"</string>
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 620718d..190341b 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ഇത് ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"തുറക്കുക"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച്, <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കാൻ ആക്‌സ‌സ് നൽകുക"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ഉപയോഗിച്ച്, <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കാൻ ആക്‌സ‌സ് നൽകുക"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ആക്‌സസ് നൽകുക"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ഇത് ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"എഡിറ്റുചെയ്യുക"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"കോൾ സ്വീകരിക്കണോ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"എല്ലായ്പ്പോഴും"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ഒരിക്കൽ മാത്രം"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ക്രമീകരണം"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, ഔദ്യോഗിക പ്രൊഫൈലിനെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ടാബ്‌ലെറ്റ്"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ടിവി"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓൺ ചെയ്തിരിക്കുന്നു"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫ് ചെയ്തിരിക്കുന്നു"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"നിലവിലെ ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കാൻ വീണ്ടും ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കുക"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"നിങ്ങൾ ഉപയോഗസഹായി ബട്ടൺ ടാപ്പുചെയ്യുമ്പോൾ ഉപയോഗിക്കുന്നതിന് ഒരു ഫീച്ചർ തിരഞ്ഞെടുക്കുക:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ഫീച്ചറുകൾ മാറ്റുന്നതിന് ഉപയോഗസഹായി ബട്ടൺ സ്‌പർശിച്ചുപിടിക്കുക."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"മാഗ്നിഫിക്കേഷൻ"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ക്യാമറ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"മൈക്രോഫോൺ"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"നിങ്ങളുടെ സ്‌ക്രീനിലെ മറ്റ് ആപ്പുകൾക്ക് മുകളിൽ പ്രദർശിപ്പിക്കുന്നു"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"ലോഡ് ചെയ്യുന്നു"</string>
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index c0b23fc..f22974d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Нээх"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ашиглан нээх"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Нээх"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосыг дараахаар нээх хандалт өгөх"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосыг <xliff:g id="APPLICATION">%2$s</xliff:g>-р нээх хандалт өгөх"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Хандалт өгөх"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Засварлах"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ашиглан засварлах"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Засах"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Дуудлагыг зөвшөөрөх үү?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Байнга"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Нэг удаа"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Тохиргоо"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ажлын профайлыг дэмждэггүй"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tелевиз"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Өнгөний засвар"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаасан"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраасан"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Одоогийн хүртээмжит онцлогийг эхлүүлэхийн тулд нэвтрэлтийн товчлолыг ашиглах"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Хүртээмжийн товчлуурыг товших үедээ ашиглах онцлогийг сонгоно уу:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Онцлогийг өөрчлөхийн тулд Хүртээмжийн товчлуурыг дараад хүлээнэ үү."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Томруулах"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камер"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"таны дэлгэцэд бусад аппын дээр харуулж байна"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Ачаалж байна"</string>
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f3d6b4b..1792887 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"यासह उघडा"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s सह उघडा"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"उघडा"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"सह <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडण्याचा अ‍ॅक्सेस द्या"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> सह <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडण्याचा अ‍ॅक्सेस द्या"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"अ‍ॅक्सेस द्या"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"सह संपादित करा"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s सह संपादित करा"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"संपादित करा"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकारायचा?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"नेहमी"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"फक्त एकदाच"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग्ज"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाईलचे समर्थन करीत नाही"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"टॅबलेट"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीव्ही"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"रंग सुधारणा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> चालू केली"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केली"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"सध्याचे अॅक्सेसिबिलिटी वैशिष्‍ट्य पुन्हा सुरू करण्‍यासाठी अॅक्सेसिबिलिटी शॉर्टकट वापरा"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तुम्ही प्रवेशयोग्यता बटण दाबल्यावर वापरण्यासाठी वैशिष्ट्य निवडा:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"वैशिष्ट्ये बदलण्यासाठी, प्रवेशयोग्यता बटणाला स्पर्श करा आणि धरून ठेवा."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"मोठे करणे"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"कॅमेरा"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"मायक्रोफोन"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"तुमच्‍या स्‍क्रीनवर इतर अॅप्‍सवर डिस्‍प्‍ले करत आहे"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"लोड होत आहे"</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0eb022a..1055ca6 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Berikan akses untuk membuka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Berikan akses untuk membuka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sentiasa"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Tetapan"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak menyokong profil kerja"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Pembetulan Warna"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan kebolehaksesan menghidupkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Kebolehaksesan mematikan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Kebolehaksesan sekali lagi untuk memulakan ciri kebolehaksesan semasa"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih ciri yang hendak digunakan apabila anda mengetik butang Kebolehaksesan:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk menukar ciri, sentuh &amp; tahan butang Kebolehaksesan."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"dipaparkan di atas apl lain pada skrin anda"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Memuatkan"</string>
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 1c5f0c7..651affc 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"...ဖြင့် ဖွင့်မည်"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ဖြင့် ဖွင့်မည်"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ဖွင့်ပါ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို အ​ောက်ပါဖြင့် ဖွင့်ခွင့်ပေးပါ-"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို <xliff:g id="APPLICATION">%2$s</xliff:g> ဖြင့် ဖွင့်ခွင့်ပေးပါ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ဖွင့်ခွင့်ပေးရန်"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"...နှင့် တည်းဖြတ်ရန်"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s နှင့် တည်းဖြတ်ရန်"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"တည်းဖြတ်ပါ"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ဖုန်းခေါ်ဆိုမှုကို လက်ခံမလား?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"အမြဲတမ်း"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"တစ်ခါတည်း"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ဆက်တင်များ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"တက်ဘလက်"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"တီဗွီ"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"အရောင်ပြင်ဆင်ခြင်း"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ဖွင့်လိုက်ပါသည်"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ပိတ်လိုက်ပါသည်"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"လက်ရှိ အသုံးလွယ်ရေး ဝန်ဆောင်မှုကို စတင်ရန် အသုံးလွယ်ရေး ဖြတ်လမ်းလင့်ခ်ကို သုံးပါ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့သည့်အခါ အသုံးပြုမည့် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ−"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ဝန်ဆောင်မှုများကို ပြောင်းလဲရန် အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့၍ ထိထားပါ။"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ချဲ့ခြင်း"</string>
@@ -1976,5 +1980,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ကင်မရာ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"မိုက်ခရိုဖုန်း"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"သင့်မျက်နှာပြင်ပေါ်ရှိ အခြားအက်ပ်များပေါ်တွင် ပြသခြင်း"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ပုံမှန်မုဒ်အတွက် အချက်အလက်ပြသည့် အကြောင်းကြားချက်"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ပုံမှန်အားသွင်းမှုမပြုလုပ်မီ ဘက်ထရီကုန်သွားနိုင်သည်"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ဘက်ထရီသက်တမ်းကို တိုးမြှင့်ရန် \'ဘက်ထရီအားထိန်း\' စတင်ပြီးပါပြီ"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"တင်နေသည်"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 233b98a..1f70767 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Åpne med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åpne med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åpne"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Gi tilgang til å åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Gi tilgang til å åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Gi tilgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Endre"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare anropet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bare én gang"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Innstillinger"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s støtter ikke arbeidsprofiler"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Nettbrett"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Google TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Fargekorrigering"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Snarveien for tilgjengelighet slo på <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Snarveien for tilgjengelighet slo av <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Bruk tilgjengelighetssnarveien igjen for å starte den nåværende tilgjengelighetsfunksjonen"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Velg en funksjon du vil bruke når du trykker på Tilgjengelighet-knappen:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"For å endre funksjoner, trykk på og hold inne Tilgjengelighet-knappen."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørring"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"vises over andre apper på skjermen"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Laster inn"</string>
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0b2362a..d278fbe 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1132,6 +1132,9 @@
     <!-- no translation found for whichViewApplicationNamed (2286418824011249620) -->
     <skip />
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोल्नुहोस्"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"निम्नमार्फत <xliff:g id="HOST">%1$s</xliff:g>का लिंकहरू खोल्न पहुँच दिनुहोस्‌"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>मार्फत <xliff:g id="HOST">%1$s</xliff:g>का लिंकहरू खोल्न पहुँच दिनुहोस्‌"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"पहुँच दिनुहोस्"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"सँग सम्पादन गर्नुहोस्"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for whichEditApplicationNamed (1775815530156447790) -->
@@ -1572,6 +1575,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"कल स्वीकार गर्नुहुन्छ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"सधैँ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"एक पटक मात्र"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिङहरू"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s  कार्य प्रोफाइल समर्थन गर्दैन"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ट्याब्लेट"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1651,7 +1655,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"रङ सच्याउने सुविधा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई सक्रिय पार्‍यो"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई निष्क्रिय पार्‍यो"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"हालको पहुँचसम्बन्धी सुविधा प्रयोग गर्न फेरि पहुँचसम्बन्धी सर्टकट प्रयोग गर्नुहोस्"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तपाईंले पहुँच सम्बन्धी बटनलाई ट्याप गर्दा प्रयोग गर्नुपर्ने सुविधा रोज्नुहोस्:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाहरूलाई बदल्न, पहुँच सम्बन्धी बटनलाई छोएर थिची राख्नुहोस्।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"म्याग्निफिकेसन"</string>
@@ -1981,5 +1985,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"क्यामेरा"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"माइक्रोफोन"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमा प्रदर्शन गरिँदै छ"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"लोड गर्दै"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 996b700..752fbc2 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Openen met"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Openen met %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Openen"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Toegang verlenen om links naar <xliff:g id="HOST">%1$s</xliff:g> te openen met"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Toegang verlenen om links naar <xliff:g id="HOST">%1$s</xliff:g> te openen met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Toegang geven"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bewerken met"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Bewerken met %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Bewerken"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Gesprek accepteren?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altijd"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Één keer"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellingen"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ondersteunt werkprofielen niet"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurcorrectie"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik de snelkoppeling voor toegankelijkheid nogmaals om de huidige toegankelijkheidsfunctie te starten"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies een functie om te gebruiken wanneer je op de knop Toegankelijkheid tikt:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Als je functies wilt wijzigen, tik je op de knop Toegankelijkheid en houd je deze vast."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfoon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wordt weergegeven vóór andere apps op je scherm"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Informatiemelding voor routinemodus"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"De batterij raakt mogelijk leeg voordat deze normaal gesproken wordt opgeladen"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterijbesparing is geactiveerd om de batterijduur te verlengen"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Laden"</string>
 </resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 27b7d5d..f2c0f62 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ସହିତ ଖୋଲନ୍ତୁ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ସହିତ ଖୋଲନ୍ତୁ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ଖୋଲନ୍ତୁ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ଏହା ସହିତ ଲିଙ୍କ ଥିବା <xliff:g id="HOST">%1$s</xliff:g> ଖୋଲିବା ପାଇଁ ଆକ୍ସେସ୍ ଦିଅନ୍ତୁ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ସହିତ ଲିଙ୍କ ଥିବା <xliff:g id="HOST">%1$s</xliff:g> ଖୋଲିବା ପାଇଁ ଆକ୍ସେସ୍ ଦିଅନ୍ତୁ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ଆକ୍ସେସ୍‌ ଦିଅନ୍ତୁ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ସହିତ ଏଡିଟ୍‌ କରନ୍ତୁ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sରେ ସଂଶୋଧନ କରନ୍ତୁ"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ଏଡିଟ୍‌ କରନ୍ତୁ"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"କଲ୍‍ ସ୍ୱୀକାର କରିବେ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ସର୍ବଦା"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ଥରେ ମାତ୍ର"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ସେଟିଂସ୍"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ୱର୍କ ପ୍ରୋଫାଇଲ୍‌କୁ ସପୋର୍ଟ କରୁନାହିଁ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ଟାବଲେଟ୍‌"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍‍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅନ୍‍ କରାଯାଇଛି"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍‍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅଫ୍‍ କରାଯାଇଛି"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ବର୍ତ୍ତମାନର ଆକ୍ସେସିବିଲିଟୀ ବୈଶିଷ୍ଟ୍ୟ ଆରମ୍ଭ କରିବାକୁ ପୁଣି ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟ୍‍କର୍ଟ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍‍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ଆପଣ ଆକ୍ସେସବିଲିଟି ବଟନ୍‍ ଟାପ୍‍ କରିବା ବେଳେ ଏକ ବୈଶିଷ୍ଟ୍ୟ ବ୍ୟବହାର କରିବାକୁ ବାଛନ୍ତୁ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇବାକୁ, ଆକ୍ସେସବିଲିଟି ବଟନ୍‍ ସ୍ପର୍ଶ କରନ୍ତୁ ଓ ଧରିରଖନ୍ତୁ।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ମ୍ୟାଗ୍ନିଫିକେସନ୍‍"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"କ୍ୟାମେରା"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ମାଇକ୍ରୋଫୋନ୍"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍ ଉପରେ ଥିବା ଅନ୍ୟ ଆପ୍‌ ଉପରେ ଦେଖାଦେବ"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"ଲୋଡ୍ ହେଉଛି"</string>
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index eacf006..266b226 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ਨਾਲ ਖੋਲ੍ਹੋ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ਨਾਲ ਖੋਲ੍ਹੋ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ਖੋਲ੍ਹੋ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ਇਸ ਨਾਲ <xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਪਹੁੰਚ ਦਿਓ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ <xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਪਹੁੰਚ ਦਿਓ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ਪਹੁੰਚ ਦਿਓ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ਇਸ ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ਕੀ ਕਾਲ ਸਵੀਕਾਰ ਕਰਨੀ ਹੈ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ਹਮੇਸ਼ਾਂ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ਕੇਵਲ ਇੱਕ ਵਾਰ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ਟੈਬਲੈੱਟ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ਰੰਗ ਸੁਧਾਈ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ਮੌਜੂਦਾ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ \'ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ\' ਦੀ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰੋ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਟੈਪ ਕੀਤੇ ਜਾਣ \'ਤੇ ਵਰਤਣ ਲਈ ਕੋਈ ਵਿਸ਼ੇਸ਼ਤਾ ਚੁਣੋ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ਵੱਡਦਰਸ਼ੀਕਰਨ"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ਕੈਮਰਾ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਹੋਰਾਂ ਐਪਾਂ ਉੱਪਰ ਦਿਖਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b2bb7b0..a86d5a6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otwórz w aplikacji"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otwórz w aplikacji %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otwórz"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Przyznaj uprawnienia do otwierania linków z <xliff:g id="HOST">%1$s</xliff:g> w:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Przyznaj uprawnienia do otwierania linków z <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udziel uprawnień"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edytuj w aplikacji"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edytuj w aplikacji %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edytuj"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tylko raz"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ustawienia"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nie obsługuje profilu do pracy"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telewizor"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcja kolorów"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Użyj ponownie skrótu ułatwień dostępu, by uruchomić bieżące ułatwienie dostępu"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wybierz funkcję używaną po kliknięciu przycisku ułatwień dostępu."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Aby zmienić funkcje, kliknij i przytrzymaj przycisk ułatwień dostępu."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Powiększenie"</string>
@@ -2045,5 +2049,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Aparat"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wyświetla się nad innymi aplikacjami na ekranie"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Powiadomienie z informacją o trybie rutynowym"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Ładuję"</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index b1a1d39..44f8478 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com o app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"exibindo sobre outros apps na sua tela"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informação do modo rotina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"A bateria pode acabar antes da recarga normal"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"A \"Economia de bateria\" foi ativada para aumentar a duração da carga"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Carregando"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ec4cf8c..f7ffa1d 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceda acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceda acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com a aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Apenas uma vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Definições"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não suporta o perfil de trabalho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção da cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O Atalho de acessibilidade ativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O Atalho de acessibilidade desativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilize novamente o atalho de acessibilidade para iniciar a funcionalidade de acessibilidade atual."</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Prima sem soltar as teclas de volume durante três segundos para utilizar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha uma funcionalidade para utilizar quando tocar no botão Acessibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar as funcionalidades, toque sem soltar no botão Acessibilidade."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"sobrepõe-se a outras aplicações no ecrã"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informações do Modo rotina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Pode ficar sem bateria antes do carregamento habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Poupança de bateria ativada para prolongar a duração da bateria"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"A carregar…"</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b1a1d39..44f8478 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com o app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"exibindo sobre outros apps na sua tela"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informação do modo rotina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"A bateria pode acabar antes da recarga normal"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"A \"Economia de bateria\" foi ativada para aumentar a duração da carga"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Carregando"</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5b36b9a..f3303c4 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1148,6 +1148,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Deschideți cu"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Deschideți cu %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Deschideți"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Permiteți accesul pentru a deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Permiteți accesul pentru a deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permiteți accesul"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editați cu"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editați cu %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editați"</string>
@@ -1589,6 +1592,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Acceptați apelul?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Numai o dată"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setări"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nu acceptă profilul de serviciu"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletă"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1673,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corecția culorii"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Comanda rapidă de accesibilitate a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Comanda rapidă de accesibilitate a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Folosiți din nou comanda rapidă Accesibilitate pentru a porni funcția de accesibilitate prezentă"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Apăsați ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Alegeți o funcție pe care să o folosiți când atingeți butonul Accesibilitate:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pentru a schimba funcțiile, atingeți lung butonul Accesibilitate."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Mărire"</string>
@@ -2010,5 +2014,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cameră foto"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se afișează peste alte aplicații de pe ecran"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Se încarcă"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ac7908c0..fde1c5d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Открыть с помощью приложения:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Открыть с помощью приложения \"%1$s\""</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Открыть"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Предоставьте доступ, чтобы открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> в приложении"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Предоставьте доступ, чтобы открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> в приложении <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Открыть доступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редактировать с помощью приложения:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактировать с помощью приложения \"%1$s\""</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Изменить"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ответить?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Всегда"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Только сейчас"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддерживает рабочие профили"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшетный ПК"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Коррекция цвета"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> включен"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> отключен"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Чтобы активировать выбранные специальные возможности, воспользуйтесь быстрым включением ещё раз"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберите функцию, которая запускается при нажатии кнопки специальных возможностей:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Чтобы изменить функцию, удерживайте кнопку специальных возможностей."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увеличение"</string>
@@ -2045,5 +2049,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх других окон"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Загрузка"</string>
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 6486f3a..baa0387 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1130,6 +1130,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"සමඟ විවෘත කරන්න"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s සමඟ විවෘත කරන්න"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"විවෘත කරන්න"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"මේවා මඟින් <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කිරීමට ප්‍රවේශය දෙන්න"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> මඟින් <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කිරීමට ප්‍රවේශය දෙන්න"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ප්‍රවේශය දෙන්න"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"සමඟ සංස්කරණය කරන්න"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s සමඟ සංස්කරණය කරන්න"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"සංස්කරණය"</string>
@@ -1568,6 +1571,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ඇමතුම පිළිගන්නවාද?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"සැම විටම"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"එක් වාරයයි"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"සැකසීම්"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s කාර්යාල පැතිකඩ සඳහා සහාය ලබනොදේ."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ටැබ්ලට්ය"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"රූපවාහිනී"</string>
@@ -1647,7 +1651,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"වර්ණ නිවැරදි කිරීම"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ප්‍රවේශ්‍යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාත්මක කරන ලදී"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ප්‍රවේශ්‍යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාවිරහිත කරන ලදී"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"වර්තමාන ප්‍රවේශ්‍යතා විශේෂංගය ආරම්භ කිරීම සඳහා ප්‍රවේශ්‍යතා කෙටි මග භාවිතා කරන්න"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ඔබ ප්‍රවේශ්‍යතා බොත්තම තට්ටු කරන විට භාවිතා කිරීමට අංගයක් තෝරාගන්න:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"අංග වෙනස් කිරීමට ප්‍රවේශ්‍යතා බොත්තම ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"විශාලනය"</string>
@@ -1977,5 +1981,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"කැමරාව"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"මයික්‍රෆෝනය"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ඔබගේ තිරය මත වෙනත් යෙදුම්වලට උඩින් සංදර්ශනය කරමින්"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"දිනචරියා ප්‍රකාර තතු දැනුම්දීම"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"බැටරිය සුපුරුදු ආරෝපණයට පෙර ඉවර විය හැක"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"බැටරි සුරැකුම බැටරි ආයු කාලය දීර්ඝ කිරීමට සක්‍රිය කෙරිණි"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"පූරණය කරමින්"</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 66d6ef6..2942537 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvoriť v aplikácii"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvoriť v aplikácii %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvoriť"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Udeľte prístup na otváranie odkazov <xliff:g id="HOST">%1$s</xliff:g> pomocou aplikácie"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Udeľte prístup na otváranie odkazov <xliff:g id="HOST">%1$s</xliff:g> pomocou aplikácie <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udeliť prístup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Upraviť pomocou"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upraviť v aplikácii %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Upraviť"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prijať hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Len raz"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavenia"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Spúšťač %1$s nepodporuje pracovné profily"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televízor"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Úprava farieb"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skratka dostupnosti zapla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skratka dostupnosti vypla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znova použite skratku dostupnosti, čím sprístupníte aktuálnu funkciu dostupnosti"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Klepnutím na tlačidlo dostupnosti vyberte požadovanú funkciu:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ak chcete zmeniť funkcie, klepnite na tlačidlo dostupnosti a podržte ho"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Priblíženie"</string>
@@ -2045,5 +2049,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparát"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofón"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"sa zobrazuje cez ďalšie aplikácie na obrazovke"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Načítava sa"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index dcaa4f5..d3f0872 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Odpiranje z aplikacijo"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Odpiranje z aplikacijo %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Odpiranje"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Omogočanje dostopa za odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Omogočanje dostopa za odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogoči dostop"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Urejanje z aplikacijo"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Urejanje z aplikacijo %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Urejanje"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ali želite sprejeti klic?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vedno"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo tokrat"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavitve"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podpira delovnega profila"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablični računalnik"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Popravljanje barv"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Če želite zagnati trenutno funkcijo za ljudi s posebnimi potrebami, znova uporabite bližnjico funkcij za ljudi s posebnimi potrebami"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izberite funkcijo, ki jo želite uporabljati, ko se dotaknete gumba »Dostopnost«:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Če želite spremeniti funkcije, se dotaknite gumba »Dostopnost« in ga pridržite."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povečava"</string>
@@ -2045,5 +2049,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparat"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prekriva druge aplikacije na zaslonu"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Nalaganje"</string>
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 413ff8a..89afb1a 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Hap me"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Hap me %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Hap"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Jep qasje për të hapur lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Jep qasje për të hapur lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Jep qasje"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redakto me"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redakto me %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redakto"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Dëshiron ta pranosh telefonatën?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Gjithmonë"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Vetëm një herë"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cilësimet"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nuk e mbështet profilin e punës"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizori"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korrigjimi i ngjyrës"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Shkurtorja e qasshmërisë e aktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Shkurtorja e qasshmërisë e çaktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Përdor përsëri \"Shkurtoren e qasshmërisë\" për të nisur funksionin aktual të qasshmërisë"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Zgjidh një funksion për ta përdorur kur troket butonin e \"Qasshmërisë\":"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Për të ndryshuar funksionet, prek dhe mbaj butonin e \"Qasshmërisë\"."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zmadhimi"</string>
@@ -1976,5 +1980,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"po shfaqet mbi aplikacionet e tjera në ekranin tënd"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Njoftimi i informacionit të \"Modalitetit rutinë\""</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateria mund të mbarojë përpara ngarkimit të zakonshëm"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"\"Kursyesi i baterisë\" u aktivizua për të zgjatur jetëgjatësinë e baterisë"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Po ngarkohet"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8f8fe0e..19f88cf 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1148,6 +1148,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отворите помоћу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отворите помоћу апликације %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дозволите да се линкови <xliff:g id="HOST">%1$s</xliff:g> отварају помоћу"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дозволите да <xliff:g id="APPLICATION">%2$s</xliff:g> отвара линикове <xliff:g id="HOST">%1$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи приступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Измените помоћу"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измените помоћу апликације %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Измени"</string>
@@ -1589,6 +1592,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Желите ли да прихватите позив?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Увек"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само једном"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Подешавања"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не подржава пословни профил"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТВ"</string>
@@ -1669,7 +1673,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција боја"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Пречица за приступачност је укључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Пречица за приступачност је искључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Употребите поново пречицу за приступачност да бисте покренули актуелну функцију приступачности"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изаберите функцију која ће се користити када додирнете дугме за приступачност:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Притисните и задржите дугме за приступачност да бисте мењали функције."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увећање"</string>
@@ -2010,5 +2014,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"приказује се на екрану док користите друге апликације"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Обавештење о информацијама Рутинског режима"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батерија ће се можда испразнити пре уобичајеног пуњења"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Уштеда батерије је активирана да би се продужило трајање батерије"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Учитава се"</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cd5580d..fcae364 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Öppna med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Öppna med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öppna"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Tillåt att länkar från <xliff:g id="HOST">%1$s</xliff:g> öppnas med"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Tillåt att länkar från <xliff:g id="HOST">%1$s</xliff:g> öppnas med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ge åtkomst"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redigera med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigera med %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redigera"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vill du ta emot samtal?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Inställningar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Surfplatta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Färgkorrigering"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiverades av Aktivera tillgänglighet snabbt"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> inaktiverades av Aktivera tillgänglighet snabbt"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Använd Aktivera tillgänglighet snabbt en gång till om du vill aktivera tillgänglighetsfunktionen i fråga"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Välj en funktion som ska användas när du trycker på tillgänglighetsknappen:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryck länge på tillgänglighetsknappen för att ändra funktioner."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Förstoring"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"visar över andra appar på mobilen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Avisering om rutinläge"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batteriet kan ta slut innan du brukar ladda det"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterisparläget har aktiverats för att utöka batteritiden"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Läser in"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index bc3e4ad..be7c301 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Fungua ukitumia"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Fungua ukitumia %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Fungua"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Ipe <xliff:g id="HOST">%1$s</xliff:g> ruhusa ya kufungua viungo kwa kutumia"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Ipe <xliff:g id="HOST">%1$s</xliff:g> ruhusa ya kufungua viungo kwa kutumia <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Idhinisha ufikiaji"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Badilisha kwa"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Badilisha kwa %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Badilisha"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kubali simu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Kila mara"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Mara moja tu"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mipangilio"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s haitumii wasifu wa kazini"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Kompyuta kibao"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Runinga"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Usahihishaji wa rangi"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Tumia njia ya Mkato wa Zana za walio na matatizo ya kuona au kusikia tena ili kuanzisha kipengele kilichopo cha walio na matatizo ya kuona au kusikia"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chagua kipengele utakachotumia, ukigonga Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ili kubadilisha vipengele, gusa na ushikile Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukuzaji"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Maikrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"inachomoza kwenye programu zingine katika skrini yako"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Arifa ya maelezo ya Hali ya Kawaida"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Huenda betri itakwisha chaji mapema"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Imewasha Kiokoa Betri ili kurefusha muda wa matumizi ya betri"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Inapakia"</string>
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 22da7b0..117f071 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"இதன்மூலம் திற"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s மூலம் திற"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"திற"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"மூலம் <xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளைத் திறப்பதற்கான அணுகலை வழங்குதல்"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> மூலம் <xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளைத் திறப்பதற்கான அணுகலை வழங்குதல்"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"அணுகலை வழங்கு"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"இதன் மூலம் திருத்து"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s மூலம் திருத்து"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"மாற்று"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"அழைப்பை ஏற்கவா?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"எப்போதும்"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"இப்போது மட்டும்"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"அமைப்புகள்"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s பணி சுயவிவரத்தை ஆதரிக்காது"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"டேப்லெட்"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"டிவி"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"வண்ணத் திருத்தம்"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ இயக்கியது"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ முடக்கியது"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"தற்போதுள்ள அணுகல்தன்மை அம்சத்தை மீண்டும் தொடங்க ’அணுகல்தன்மை ஷார்ட்கட்டைப்’ பயன்படுத்தவும்"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"அணுகல்தன்மைப் பொத்தானைத் தட்டி, பயன்படுத்துவதற்கான அம்சத்தைத் தேர்ந்தெடுக்கவும்:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"அம்சங்களை மாற்ற, அணுகல்தன்மைப் பொத்தானைத் தொட்டுப் பிடித்திருக்கவும்."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"பெரிதாக்கல்"</string>
@@ -1976,5 +1980,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"கேமரா"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"மைக்ரோஃபோன்"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"உங்கள் திரையில் உள்ள பிற பயன்பாடுகளின் மேல் காட்டுகிறது"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"வழக்கமான பேட்டரி சேமிப்பானுக்கான விவர அறிவிப்பு"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"வழக்கமாகச் சார்ஜ் செய்வதற்கு முன்பே பேட்டரி தீர்ந்துபோகக்கூடும்"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"பேட்டரி நிலையை நீட்டிக்க பேட்டரி சேமிப்பான் இயக்கப்பட்டுள்ளது"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ஏற்றுகிறது"</string>
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 1cc0274..654585d 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"దీనితో తెరువు"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sతో తెరువు"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"తెరువు"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను తెరవడానికి యాక్సెస్ ఇవ్వండి"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>తో <xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను తెరవడానికి యాక్సెస్ ఇవ్వండి"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"యాక్సెస్ ఇవ్వండి"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"దీనితో సవరించు"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sతో సవరించు"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"సవరించు"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"కాల్‌ను ఆమోదించాలా?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ఎల్లప్పుడూ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ఒకసారి"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"సెట్టింగ్‌లు"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s కార్యాలయ ప్రొఫైల్‌కు మద్దతు ఇవ్వదు"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"టాబ్లెట్"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"టీవీ"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"రంగు సవరణ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"యాక్సెస్ సామర్థ్య షార్ట్‌కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"యాక్సెస్ సామర్థ్య షార్ట్‌కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ప్రస్తుత యాక్సెస్ సౌలభ్య ఫీచర్‌ను ఉపయోగించడానికి యాక్సెసిబిలిటీ షార్ట్‌కట్‌ను మళ్లీ ప్రారంభించండి"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"యాక్సెస్ సామర్థ్య బటన్‌ను మీరు నొక్కినప్పుడు ఉపయోగించాల్సిన ఒక ఫీచర్‌ను ఎంచుకోండి:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ఫీచర్లను మార్చడానికి, యాక్సెస్ సామర్థ్య బటన్‌ను నొక్కి &amp; పట్టుకోండి."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"మాగ్నిఫికేషన్"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"కెమెరా"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"మైక్రోఫోన్"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"మీ స్క్రీన్‌పై ఇతర యాప్‌ల ద్వారా ప్రదర్శించబడుతోంది"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"లోడవుతోంది"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2edf57c..ca8f529 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"เปิดด้วย"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"เปิดด้วย %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"เปิด"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ให้สิทธิ์ในการเปิดลิงก์ของ <xliff:g id="HOST">%1$s</xliff:g> โดยใช้"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ให้สิทธิ์ในการเปิดลิงก์ของ <xliff:g id="HOST">%1$s</xliff:g> โดยใช้ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ให้สิทธิ์"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"แก้ไขด้วย"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"แก้ไขด้วย %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"แก้ไข"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"เฉพาะครั้งนี้"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"การตั้งค่า"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ไม่สนับสนุนโปรไฟล์งาน"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"แท็บเล็ต"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ทีวี"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"การปรับแก้สี"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ทางลัดการเข้าถึงเปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ทางลัดการเข้าถึงปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ใช้ทางลัดการช่วยเหลือพิเศษอีกครั้งเพื่อเริ่มฟีเจอร์การช่วยเหลือพิเศษปัจจุบัน"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"เลือกฟีเจอร์ที่จะใช้เมื่อคุณแตะปุ่ม \"การเข้าถึงพิเศษ\":"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"หากต้องการเปลี่ยนฟีเจอร์ ให้แตะปุ่ม \"การเข้าถึงพิเศษ\" ค้างไว้"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"การขยาย"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"กล้อง"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ไมโครโฟน"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"แสดงทับแอปอื่นๆ บนหน้าจอ"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"กำลังโหลด"</string>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f7995f7..31d906f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buksan gamit ang"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buksan gamit ang %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buksan"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Magbigay ng access para buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> sa"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Magbigay ng access para buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> sa <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Bigyan ng access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"I-edit gamit ang"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"I-edit gamit ang %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"I-edit"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Tanggapin ang tawag?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Palagi"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Isang beses lang"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mga Setting"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Hindi sinusuportahan ng %1$s ang profile sa trabaho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Pagwawasto ng Kulay"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Na-on ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Na-off ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gamiting muli ang Shortcut sa Pagiging Naa-access para simulan ang kasalukuyang feature ng pagiging naa-access"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pumili ng feature na gagamitin kapag na-tap mo ang button ng Pagiging Naa-access:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Upang baguhin ang mga feature, pindutin nang matagal ang button ng Pagiging Naa-access."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pag-magnify"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikropono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ipinapakita sa ibabaw ng ibang app sa iyong screen"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Naglo-load"</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 761eba6..75b19a9 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Şununla aç:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ile aç"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Aç"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Şununla <xliff:g id="HOST">%1$s</xliff:g> bağlantılarını açma izni verin"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasıyla <xliff:g id="HOST">%1$s</xliff:g> bağlantılarını açma izni verin"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Erişim ver"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Şununla düzenle:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ile düzenle"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Düzenle"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Çağrı kabul edilsin mi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Her zaman"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Yalnızca bir defa"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, iş profilini desteklemiyor"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Renk Düzeltme"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini açtı"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kapattı"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Geçerli erişilebilirlik özelliğini başlatmak için Erişilebilirlik Kısayolu\'nu tekrar kullanın"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Erişilebilirlik düğmesine dokunduğunuzda kullanmak üzere bir özellik seçin:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Özellikleri değiştirmek için Erişilebilirlik düğmesine dokunup basılı tutun."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Büyütme"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ekranınızdaki diğer uygulamaların üzerinde görüntüleniyor"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Yükleniyor"</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e7e99ae..933d04a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1168,6 +1168,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Відкрити за допомогою"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Відкрити за допомогою %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Відкрити"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дозвольте відкривати посилання на сайт <xliff:g id="HOST">%1$s</xliff:g> у додатку"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дозвольте відкривати посилання на сайт <xliff:g id="HOST">%1$s</xliff:g> у додатку <xliff:g id="APPLICATION">%2$s</xliff:g>."</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволити"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редагувати за допомогою"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редагувати за допомогою %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Редагувати"</string>
@@ -1612,6 +1615,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прийняти виклик?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Завжди"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Лише цього разу"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налаштування"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не підтримує робочий профіль"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшетний ПК"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевізор"</string>
@@ -1693,7 +1697,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекція кольорів"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Ярлик спеціальних можливостей увімкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Ярлик спеціальних можливостей вимкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Щоб запустити поточну функцію спеціальних можливостей, знову скористайтеся відповідним ярликом"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Виберіть функцію для кнопки спеціальних можливостей:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Щоб змінити функцію, натисніть і втримуйте кнопку спеціальних можливостей."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Збільшення"</string>
@@ -2045,5 +2049,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Мікрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх інших додатків на екрані"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Завантаження"</string>
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index e33f3f2..20f7621 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"اس کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏%1$s کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"کھولیں"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"اس کے ساتھ <xliff:g id="HOST">%1$s</xliff:g> لنکس کو کھولنے کے لیے رسائی ديں"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> کے ساتھ <xliff:g id="HOST">%1$s</xliff:g> لنکس کو کھولنے کے لیے رسائی ديں"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"رسائی دیں"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"اس کے ساتھ ترمیم کریں"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏%1$s کے ساتھ ترمیم کریں"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ترمیم کریں"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"کال قبول کریں؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ہمیشہ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"بس ایک مرتبہ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ترتیبات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s دفتری پروفائل کا تعاون نہیں کرتا ہے"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ٹیبلیٹ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"رنگ کی تصحیح"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آن کر دیا"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آف کر دیا"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"موجودہ ایکسیسبیلٹی خصوصیت کو شروع کرنے کیلئے دوبارہ ایکسیسبیلٹی شارٹ کٹ استعمال کریں"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ایکسیسبیلٹی بٹن پر تھپتھپانے وقت استعمال کرنے کیلئے ایک خصوصیت چنیں:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"خصوصیات تبدیل کرنے کیلئے، ایکسیسبیلٹی بٹن ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"میگنیفکیشن"</string>
@@ -1976,5 +1980,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"کیمرا"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"مائیکروفون"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"آپ کی اسکرین پر دیگر ایپس پر دکھایا جا رہا ہے"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"لوڈ ہو رہا ہے"</string>
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 7742c3e..3f20dc1 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s bilan ochish"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ochish"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini ushbu ilova bilan ochishga ruxsat bering:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini <xliff:g id="APPLICATION">%2$s</xliff:g> bilan ochishga ruxsat bering"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ruxsat berish"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"“%1$s” yordamida tahrirlash"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Tahrirlash"</string>
@@ -1567,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Qo‘ng‘iroqni qabul qilasizmi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Har doim"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Faqat hozir"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Sozlamalar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"“%1$s” ishchi profilni qo‘llab-quvvatlamaydi"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planshet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1650,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Rangni tuzatish"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati yoqildi"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati o‘chirib qo‘yildi"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Joriy maxsus imkoniyatlar funksiyasini boshlash uchun tezkor ishga tushirishdan qayta foydalaning"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatidan foydalanish uchun ikkala ovoz balandligi tugmalarini uzoq bosib turing"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Maxsus imkoniyatlar tugmasi bosilganda ishga tushadigan funksiyani tanlang:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyalarni o‘zgartirish uchun Maxsus imkoniyatlar tugmasini bosib turing."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Kattalashtirish"</string>
@@ -1976,5 +1980,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ekranda boshqa ilovalar ustidan ochiladi"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Kun tartibi rejimi haqidagi bildirishnoma"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batareya quvvati odatdagidan ertaroq tugashi mumkin"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batareya quvvati uzoqroq ishlashi uchun Tejamkor rejim yoqildi"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Yuklanmoqda"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 86bb532..19c3913 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Mở bằng"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mở bằng %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Mở"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Cấp quyền truy cập để mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Cấp quyền truy cập để mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Cấp quyền truy cập"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Chỉnh sửa bằng"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Chỉnh sửa bằng %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Chỉnh sửa"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cài đặt"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s không hỗ trợ hồ sơ công việc"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Máy tính bảng"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Sửa màu"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Đã bật phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Đã tắt phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sử dụng lại Phím tắt hỗ trợ tiếp cận để bắt đầu tính năng hỗ trợ tiếp cận hiện tại"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chọn tính năng sẽ sử dụng khi bạn nhấn nút Trợ năng:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Để thay đổi các tính năng, hãy chạm và giữ nút Trợ năng."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Phóng to"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Máy ảnh"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrô"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"hiển thị qua các ứng dụng khác trên màn hình của bạn"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"Đang tải"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index dbb7834..6720132 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"打开方式"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用%1$s打开"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"打开"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授权使用以下应用打开 <xliff:g id="HOST">%1$s</xliff:g> 链接:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授权使用<xliff:g id="APPLICATION">%2$s</xliff:g>打开 <xliff:g id="HOST">%1$s</xliff:g> 链接"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予访问权限"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"编辑方式"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用%1$s编辑"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"编辑"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"始终"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"仅此一次"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"设置"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s不支持工作资料"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板电脑"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"电视"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"无障碍快捷方式已开启<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"无障碍快捷方式已关闭<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用无障碍快捷方式即可启动目前设置的无障碍功能"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"选择按下“无障碍”按钮时要使用的功能:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"要更改指定的功能,请触摸并按住“无障碍”按钮。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大功能"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"相机"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"麦克风"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"显示在屏幕上其他应用的上层"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"正在加载"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 6248db5..701e266 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"用於開啟的應用程式"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用 %1$s 開啟"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授予存取權以透過以下應用程式開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授予存取權以透過<xliff:g id="APPLICATION">%2$s</xliff:g>開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"使用以下選擇器編輯:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"編輯"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"只此一次"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援公司檔案"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板電腦"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"無障礙功能快速鍵已啟用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"無障礙功能快速鍵已停用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再用一次無障礙功能捷徑,就可以啟用宜家設定咗嘅無障礙功能"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"請選擇輕按「無障礙功能」按鈕時使用的功能:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更功能,可按住「無障礙功能」按鈕。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"相機"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"麥克風"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"顯示在畫面上的其他應用程式上層"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"正在載入"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 74da200..24a51bd 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟工具"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"透過 %1$s 開啟"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授權系統使用以下應用程式開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授權系統使用「<xliff:g id="APPLICATION">%2$s</xliff:g>」開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"選擇編輯工具"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"編輯"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"僅限一次"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援工作設定檔"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板電腦"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"協助工具捷徑啟用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"協助工具捷徑停用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用協助工具捷徑即可啟動目前設定的無障礙功能"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"輕觸 [協助工具] 按鈕後,選擇你想使用的功能:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更指派的功能,請按住 [協助工具] 按鈕。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
@@ -1975,5 +1979,11 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"相機"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"麥克風"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"顯示在畫面上的其他應用程式上層"</string>
+    <!-- no translation found for dynamic_mode_notification_channel_name (2348803891571320452) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_title (508815255807182035) -->
+    <skip />
+    <!-- no translation found for dynamic_mode_notification_summary (2541166298550402690) -->
+    <skip />
     <string name="car_loading_profile" msgid="3545132581795684027">"載入中"</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 93b2ae6..f819945 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1128,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Vula nge-"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Vula nge-%1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Kuvuliwe"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Nika ukufinyelela kuzixhumanisi ezivulekile ze-<xliff:g id="HOST">%1$s</xliff:g> nge-"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Nika ukufinyelela kuzixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> ezivulekile nge-<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Nikeza ukufinyel"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Hlela nge-"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Hlela nge-%1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Hlela"</string>
@@ -1566,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Amukela ucingo?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Njalo"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Kanye nje"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Izilungiselelo"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ayisekeli iphrofayela yomsebenzi"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Ithebulethi"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"I-TV"</string>
@@ -1645,7 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Ukulungiswa kombala"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Isinqamuleli sokufinyelela sivule i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Isinqamuleli sokufinyelela sivale i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sebenzisa isinqamuleli sokufinyelela futhi ukuze uqale isici samanje sokufinyelela"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Khetha isici ozosisebenzisa uma uthepha inkinobho yokufinyelela:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ukuze ushintshe izici, thinta uphinde ubambe inkinobho yokufinyelela."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukukhuliswa"</string>
@@ -1975,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Ikhamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Imakrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"iboniswa ngaphezulu kwezinye izinhlelo zokusebenza kusikrini sakho"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Isaziso solwazi lwe-Routine Mode"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Ibhethri lingaphela ngaphambi kokushaja okuvamile"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Isilondolozi sebhethri siyasebenza ngaphandle kwempilo yebhethri"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Iyalayisha"</string>
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 54f6c63..18a42bc 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -593,7 +593,7 @@
          to be set for all windows of this activity -->
     <attr name="showForAllUsers" format="boolean" />
 
-    <!-- Specifies whether an {@link android.app.Activity} should be shown on top of the the lock screen
+    <!-- Specifies whether an {@link android.app.Activity} should be shown on top of the lock screen
          whenever the lockscreen is up and the activity is resumed. Normally an activity will be
          transitioned to the stopped state if it is started while the lockscreen is up, but with
          this flag set the activity will remain in the resumed state visible on-top of the lock
@@ -2412,6 +2412,19 @@
         <attr name="showForAllUsers" />
 
         <attr name="showWhenLocked" />
+        <!-- @hide @SystemApi Specifies whether this {@link android.app.Activity} should be shown on
+             top of the lock screen whenever the lockscreen is up and this activity has another
+             activity behind it with the {@link android.R.attr#showWhenLocked} attribute set. That
+             is, this activity is only visible on the lock screen if there is another activity with
+             the {@link android.R.attr#showWhenLocked} attribute visible at the same time on the
+             lock screen. A use case for this is permission dialogs, that should only be visible on
+             the lock screen if their requesting activity is also visible.
+
+         The default value of this attribute is <code>false</code>. -->
+    <attr name="inheritShowWhenLocked" format="boolean" />
+
+
+        <attr name="inheritShowWhenLocked" />
         <attr name="turnScreenOn" />
 
         <attr name="directBootAware" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1c98c66..1feb59a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1152,6 +1152,10 @@
          Settings.System.NOTIFICATION_VIBRATION_INTENSITY more details on the constant values and
          meanings. -->
     <integer name="config_defaultNotificationVibrationIntensity">2</integer>
+    <!-- The default intensity level for ring vibrations. See
+         Settings.System.RING_VIBRATION_INTENSITY more details on the constant values and
+         meanings. -->
+    <integer name="config_defaultRingVibrationIntensity">2</integer>
 
     <bool name="config_use_strict_phone_number_comparation">false</bool>
 
@@ -3419,6 +3423,23 @@
     -->
     <string name="config_defaultAugmentedAutofillService" translatable="false"></string>
 
+    <!-- The package name for the system's app prediction service.
+         This service must be trusted, as it can be activated without explicit consent of the user.
+         Example: "com.android.intelligence/.AppPredictionService"
+    -->
+    <string name="config_defaultAppPredictionService" translatable="false"></string>
+
+    <!-- The package name for the system's content suggestions service.
+         Provides suggestions for text and image selection regions in snapshots of apps and should
+         be able to classify the type of entities in those selections.
+
+         This service must be trusted, as it can be activated without explicit consent of the user.
+         If no service with the specified name exists on the device, content suggestions wil be
+         disabled.
+         Example: "com.android.contentsuggestions/.ContentSuggestionsService"
+    -->
+    <string name="config_defaultContentSuggestionsService" translatable="false"></string>
+
     <!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
     <bool name="config_useDefaultFocusHighlight">true</bool>
 
@@ -3648,4 +3669,8 @@
          set in AndroidManifest.
          {@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} -->
     <string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string>
+
+    <!-- If device supports corner radius on windows.
+         This should be turned off on low-end devices to improve animation performance. -->
+    <bool name="config_supportsRoundedCornersOnWindows">true</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 799d9d8..b3b30e9 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2934,6 +2934,8 @@
         <public name="foregroundServiceType" />
         <public name="hasFragileUserData" />
         <public name="minAspectRatio" />
+        <!-- @hide @SystemApi -->
+        <public name="inheritShowWhenLocked" />
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 01fbf80..010accf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3275,6 +3275,8 @@
   <java-symbol type="string" name="config_defaultWellbeingPackage" />
   <java-symbol type="string" name="config_defaultContentCaptureService" />
   <java-symbol type="string" name="config_defaultAugmentedAutofillService" />
+  <java-symbol type="string" name="config_defaultAppPredictionService" />
+  <java-symbol type="string" name="config_defaultContentSuggestionsService" />
 
   <java-symbol type="string" name="notification_channel_foreground_service" />
   <java-symbol type="string" name="foreground_service_app_in_background" />
@@ -3489,6 +3491,7 @@
 
   <java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
   <java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
+  <java-symbol type="integer" name="config_defaultRingVibrationIntensity" />
 
   <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" />
 
@@ -3515,6 +3518,7 @@
   <java-symbol type="dimen" name="rounded_corner_radius" />
   <java-symbol type="dimen" name="rounded_corner_radius_top" />
   <java-symbol type="dimen" name="rounded_corner_radius_bottom" />
+  <java-symbol type="bool" name="config_supportsRoundedCornersOnWindows" />
 
   <java-symbol type="string" name="config_defaultModuleMetadataProvider" />
 
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 041fb7e..74943c7 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -43,7 +43,8 @@
     platform-test-annotations \
     compatibility-device-util \
     truth-prebuilt \
-    print-test-util-lib
+    print-test-util-lib \
+    testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 1750dac..0f83a29 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -19,28 +19,35 @@
 import static android.content.Intent.ACTION_EDIT;
 import static android.content.Intent.ACTION_VIEW;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.IApplicationThread;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.ClientTransactionItem;
 import android.app.servertransaction.ResumeActivityItem;
 import android.app.servertransaction.StopActivityItem;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.os.IBinder;
 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 android.view.Display;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+
 /**
  * Test for verifying {@link android.app.ActivityThread} class.
  * Build/Install/Run:
@@ -50,8 +57,12 @@
 @MediumTest
 public class ActivityThreadTest {
 
-    private final ActivityTestRule mActivityTestRule =
-            new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
+    // The first sequence number to try with. Use a large number to avoid conflicts with the first a
+    // few sequence numbers the framework used to launch the test activity.
+    private static final int BASE_SEQ = 10000;
+
+    private final ActivityTestRule<TestActivity> mActivityTestRule =
+            new ActivityTestRule<>(TestActivity.class, true /* initialTouchMode */,
                     false /* launchActivity */);
 
     @Test
@@ -129,6 +140,179 @@
         });
     }
 
+    @Test
+    public void testHandleActivityConfigurationChanged() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final int numOfConfig = activity.mNumOfConfigChanges;
+            applyConfigurationChange(activity, BASE_SEQ);
+            assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_DropStaleConfigurations() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // Set the sequence number to BASE_SEQ.
+            applyConfigurationChange(activity, BASE_SEQ);
+
+            final int orientation = activity.mConfig.orientation;
+            final int numOfConfig = activity.mNumOfConfigChanges;
+
+            // Try to apply an old configuration change.
+            applyConfigurationChange(activity, BASE_SEQ - 1);
+            assertEquals(numOfConfig, activity.mNumOfConfigChanges);
+            assertEquals(orientation, activity.mConfig.orientation);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_ApplyNewConfigurations() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // Set the sequence number to BASE_SEQ and record the final sequence number it used.
+            final int seq = applyConfigurationChange(activity, BASE_SEQ);
+
+            final int orientation = activity.mConfig.orientation;
+            final int numOfConfig = activity.mNumOfConfigChanges;
+
+            // Try to apply an new configuration change.
+            applyConfigurationChange(activity, seq + 1);
+            assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+            assertNotEquals(orientation, activity.mConfig.orientation);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_PickNewerPendingConfiguration() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // Set the sequence number to BASE_SEQ and record the final sequence number it used.
+            final int seq = applyConfigurationChange(activity, BASE_SEQ);
+
+            final int orientation = activity.mConfig.orientation;
+            final int numOfConfig = activity.mNumOfConfigChanges;
+
+            final ActivityThread activityThread = activity.getActivityThread();
+
+            final Configuration pendingConfig = new Configuration();
+            pendingConfig.orientation = orientation == Configuration.ORIENTATION_LANDSCAPE
+                    ? Configuration.ORIENTATION_PORTRAIT
+                    : Configuration.ORIENTATION_LANDSCAPE;
+            pendingConfig.seq = seq + 2;
+            activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+                    pendingConfig);
+
+            final Configuration newConfig = new Configuration();
+            newConfig.orientation = orientation;
+            newConfig.seq = seq + 1;
+
+            activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+                    newConfig, Display.INVALID_DISPLAY);
+            assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+            assertEquals(pendingConfig.orientation, activity.mConfig.orientation);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_OnlyAppliesNewestConfiguration()
+            throws Exception {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        final ActivityThread activityThread = activity.getActivityThread();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final Configuration config = new Configuration();
+            config.seq = BASE_SEQ;
+            config.orientation = Configuration.ORIENTATION_PORTRAIT;
+
+            activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+                    config, Display.INVALID_DISPLAY);
+        });
+
+        final int numOfConfig = activity.mNumOfConfigChanges;
+        final IApplicationThread appThread = activityThread.getApplicationThread();
+
+        activity.mConfigLatch = new CountDownLatch(1);
+        activity.mTestLatch = new CountDownLatch(1);
+
+        Configuration config = new Configuration();
+        config.seq = BASE_SEQ + 1;
+        config.smallestScreenWidthDp = 100;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        // Wait until the main thread is performing the configuration change for the configuration
+        // with sequence number BASE_SEQ + 1 before proceeding. This is to mimic the situation where
+        // the activity takes very long time to process configuration changes.
+        activity.mTestLatch.await();
+
+        config = new Configuration();
+        config.seq = BASE_SEQ + 2;
+        config.smallestScreenWidthDp = 200;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        config = new Configuration();
+        config.seq = BASE_SEQ + 3;
+        config.smallestScreenWidthDp = 300;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        config = new Configuration();
+        config.seq = BASE_SEQ + 4;
+        config.smallestScreenWidthDp = 400;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        activity.mConfigLatch.countDown();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        activity.mConfigLatch = null;
+        activity.mTestLatch = null;
+
+        // Only two more configuration changes: one with seq BASE_SEQ + 1; another with seq
+        // BASE_SEQ + 4. Configurations scheduled in between should be dropped.
+        assertEquals(numOfConfig + 2, activity.mNumOfConfigChanges);
+        assertEquals(400, activity.mConfig.smallestScreenWidthDp);
+    }
+
+    /**
+     * Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)}
+     * to try to push activity configuration to the activity for the given sequence number.
+     * <p>
+     * It uses orientation to push the configuration and it tries a different orientation if the
+     * first attempt doesn't make through, to rule out the possibility that the previous
+     * configuration already has the same orientation.
+     *
+     * @param activity the test target activity
+     * @param seq the specified sequence number
+     * @return the sequence number this method tried with the last time, so that the caller can use
+     * the next sequence number for next configuration update.
+     */
+    private int applyConfigurationChange(TestActivity activity, int seq) {
+        final ActivityThread activityThread = activity.getActivityThread();
+
+        final int numOfConfig = activity.mNumOfConfigChanges;
+        Configuration config = new Configuration();
+        config.orientation = Configuration.ORIENTATION_PORTRAIT;
+        config.seq = seq;
+        activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
+                Display.INVALID_DISPLAY);
+
+        if (activity.mNumOfConfigChanges > numOfConfig) {
+            return config.seq;
+        }
+
+        config = new Configuration();
+        config.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        config.seq = seq + 1;
+        activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
+                Display.INVALID_DISPLAY);
+
+        return config.seq;
+    }
+
     private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
         final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
                 null, 0, new MergedConfiguration(), false /* preserveWindow */);
@@ -162,6 +346,16 @@
         return transaction;
     }
 
+    private static ClientTransaction newActivityConfigTransaction(Activity activity,
+            Configuration config) {
+        final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config);
+
+        final ClientTransaction transaction = newTransaction(activity);
+        transaction.addCallback(item);
+
+        return transaction;
+    }
+
     private static ClientTransaction newTransaction(Activity activity) {
         final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
         return ClientTransaction.obtain(appThread, activity.getActivityToken());
@@ -169,5 +363,37 @@
 
     // Test activity
     public static class TestActivity extends Activity {
+        int mNumOfConfigChanges;
+        final Configuration mConfig = new Configuration();
+
+        /**
+         * A latch used to notify tests that we're about to wait for configuration latch. This
+         * is used to notify test code that preExecute phase for activity configuration change
+         * transaction has passed.
+         */
+        volatile CountDownLatch mTestLatch;
+        /**
+         * If not {@code null} {@link #onConfigurationChanged(Configuration)} won't return until the
+         * latch reaches 0.
+         */
+        volatile CountDownLatch mConfigLatch;
+
+        @Override
+        public void onConfigurationChanged(Configuration config) {
+            super.onConfigurationChanged(config);
+            mConfig.setTo(config);
+            ++mNumOfConfigChanges;
+
+            if (mConfigLatch != null) {
+                if (mTestLatch != null) {
+                    mTestLatch.countDown();
+                }
+                try {
+                    mConfigLatch.await();
+                } catch (InterruptedException e) {
+                    throw new IllegalStateException(e);
+                }
+            }
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f863356..1ed5ce4 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -27,6 +27,7 @@
 import static java.lang.reflect.Modifier.isStatic;
 
 import android.platform.test.annotations.Presubmit;
+import android.provider.Settings.Global;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -270,7 +271,6 @@
                     Settings.Global.GNSS_SATELLITE_BLACKLIST,
                     Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
                     Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
-                    Settings.Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED,
                     Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
                     Settings.Global.HDMI_CONTROL_ENABLED,
                     Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
@@ -550,7 +550,12 @@
                     Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
                     Settings.Global.BACKUP_MULTI_USER_ENABLED,
                     Settings.Global.ISOLATED_STORAGE_LOCAL,
-                    Settings.Global.ISOLATED_STORAGE_REMOTE);
+                    Settings.Global.ISOLATED_STORAGE_REMOTE,
+                    Settings.Global.APPOP_HISTORY_PARAMETERS,
+                    Settings.Global.APPOP_HISTORY_MODE,
+                    Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER,
+                    Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS);
+
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
                  Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
new file mode 100644
index 0000000..8a3ba8c
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.service.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.metrics.LogMaker;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class StatusBarNotificationTest {
+
+    private final Context mMockContext = mock(Context.class);
+    @Mock
+    private PackageManager mPm;
+
+    private static final String PKG = "com.example.o";
+    private static final int UID = 9583;
+    private static final int ID = 1;
+    private static final String TAG = "tag1";
+    private static final String CHANNEL_ID = "channel";
+    private static final String CHANNEL_ID_LONG =
+            "give_a_developer_a_string_argument_and_who_knows_what_they_will_pass_in_there";
+    private static final String GROUP_ID_1 = "group1";
+    private static final String GROUP_ID_2 = "group2";
+    private static final String GROUP_ID_LONG =
+            "0|com.foo.bar|g:content://com.foo.bar.ui/account%3A-0000000/account/";
+    private static final android.os.UserHandle USER =
+            UserHandle.of(ActivityManager.getCurrentUser());
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mMockContext.getResources()).thenReturn(
+                InstrumentationRegistry.getContext().getResources());
+        when(mMockContext.getPackageManager()).thenReturn(mPm);
+        when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+    }
+
+    @Test
+    public void testLogMaker() {
+        final LogMaker logMaker = getNotification(PKG, GROUP_ID_1, CHANNEL_ID).getLogMaker();
+
+        assertEquals(CHANNEL_ID,
+                (String) logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID));
+        assertEquals(PKG, logMaker.getPackageName());
+        assertEquals(ID, logMaker.getTaggedData(MetricsEvent.NOTIFICATION_ID));
+        assertEquals(TAG, logMaker.getTaggedData(MetricsEvent.NOTIFICATION_TAG));
+        assertEquals(GROUP_ID_1,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+    }
+
+    @Test
+    public void testLogMakerNoChannel() {
+        final LogMaker logMaker = getNotification(PKG, GROUP_ID_1, null).getLogMaker();
+
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID));
+    }
+
+    @Test
+    public void testLogMakerLongChannel() {
+        final LogMaker logMaker = getNotification(PKG, null, CHANNEL_ID_LONG).getLogMaker();
+        final String loggedId = (String) logMaker
+                .getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID);
+        assertEquals(StatusBarNotification.MAX_LOG_TAG_LENGTH, loggedId.length());
+        assertEquals(CHANNEL_ID_LONG.substring(0, 10), loggedId.substring(0, 10));
+    }
+
+    @Test
+    public void testLogMakerNoGroup() {
+        final LogMaker logMaker = getNotification(PKG, null, CHANNEL_ID).getLogMaker();
+
+        assertNull(
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+    }
+
+    @Test
+    public void testLogMakerLongGroup() {
+        final LogMaker logMaker = getNotification(PKG, GROUP_ID_LONG, CHANNEL_ID)
+                .getLogMaker();
+
+        final String loggedId = (String)
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID);
+        assertEquals(StatusBarNotification.MAX_LOG_TAG_LENGTH, loggedId.length());
+        assertEquals(GROUP_ID_LONG.substring(0, 10), loggedId.substring(0, 10));
+    }
+
+    @Test
+    public void testLogMakerOverrideGroup() {
+        StatusBarNotification sbn = getNotification(PKG, GROUP_ID_1, CHANNEL_ID);
+        assertEquals(GROUP_ID_1,
+                sbn.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+
+        sbn.setOverrideGroupKey(GROUP_ID_2);
+        assertEquals(GROUP_ID_2,
+                sbn.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+
+        sbn.setOverrideGroupKey(null);
+        assertEquals(GROUP_ID_1,
+                sbn.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+    }
+
+    private StatusBarNotification getNotification(String pkg, String group, String channelId) {
+        final Notification.Builder builder = new Notification.Builder(mMockContext, channelId)
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        if (group != null) {
+            builder.setGroup(group);
+        }
+
+        Notification n = builder.build();
+        return new StatusBarNotification(
+                pkg, pkg, ID, TAG, UID, UID, n, USER, null, UID);
+    }
+
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
new file mode 100644
index 0000000..59f3a4c
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.contentcapture;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.view.autofill.AutofillId;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Unit test for {@link ContentCaptureSessionTest}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureSessionTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ContentCaptureSessionTest {
+
+    /**
+     * Uses a spy as ContentCaptureSession is abstract but (so far) we're testing its concrete
+     * methods.
+     */
+    @Spy
+    private ContentCaptureSession mMockSession;
+
+    @Test
+    public void testNewAutofillId_invalid() {
+        assertThrows(NullPointerException.class, () -> mMockSession.newAutofillId(null, 42));
+        assertThrows(IllegalArgumentException.class,
+                () -> mMockSession.newAutofillId(new AutofillId(42, 42), 42));
+    }
+
+    @Test
+    public void testNewAutofillId_valid() {
+        final AutofillId parentId = new AutofillId(42);
+        final AutofillId childId = mMockSession.newAutofillId(parentId, 108);
+        assertThat(childId.getViewId()).isEqualTo(42);
+        assertThat(childId.getVirtualChildId()).isEqualTo(108);
+        // TODO(b/121197119): assert session id
+    }
+
+    @Test
+    public void testNotifyXXX_null() {
+        assertThrows(NullPointerException.class, () -> mMockSession.notifyViewAppeared(null));
+        assertThrows(NullPointerException.class, () -> mMockSession.notifyViewDisappeared(null));
+        assertThrows(NullPointerException.class,
+                () -> mMockSession.notifyViewTextChanged(null, "whatever", 0));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
new file mode 100644
index 0000000..995946b
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.contentcapture;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.os.Parcel;
+import android.support.test.InstrumentationRegistry;
+import android.view.View;
+import android.view.ViewStructure.HtmlInfo;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import android.widget.FrameLayout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Locale;
+
+/**
+ * Unit test for {@link ViewNode}.
+ *
+ * <p>To run it: {@code atest FrameworksCoreTests:android.view.contentcapture.ViewNodeTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ViewNodeTest {
+
+    private final Context mContext = InstrumentationRegistry.getTargetContext();
+
+    @Mock
+    private HtmlInfo mHtmlInfoMock;
+
+    @Test
+    public void testAutofillIdMethods_orphanView() {
+        View view = new View(mContext);
+        AutofillId initialId = new AutofillId(42);
+        view.setAutofillId(initialId);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(initialId);
+        assertThat(node.getParentAutofillId()).isNull();
+
+        AutofillId newId = new AutofillId(108);
+        structure.setAutofillId(newId);
+        assertThat(node.getAutofillId()).isEqualTo(newId);
+        assertThat(node.getParentAutofillId()).isNull();
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testAutofillIdMethods_parentedView() {
+        FrameLayout parent = new FrameLayout(mContext);
+        AutofillId initialParentId = new AutofillId(48);
+        parent.setAutofillId(initialParentId);
+
+        View child = new View(mContext);
+        AutofillId initialChildId = new AutofillId(42);
+        child.setAutofillId(initialChildId);
+
+        parent.addView(child);
+
+        ViewStructureImpl structure = new ViewStructureImpl(child);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(initialChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newChildId = new AutofillId(108);
+        structure.setAutofillId(newChildId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newParentId = new AutofillId(15162342);
+        parent.setAutofillId(newParentId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testAutofillIdMethods_explicitIdsConstructor() {
+        AutofillId initialParentId = new AutofillId(42);
+        ViewStructureImpl structure = new ViewStructureImpl(initialParentId, 108);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(initialParentId, 108));
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newChildId = new AutofillId(108);
+        structure.setAutofillId(newChildId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testInvalidSetters() {
+        View view = new View(mContext);
+        AutofillId initialId = new AutofillId(42);
+        view.setAutofillId(initialId);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // sanity check
+
+        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null));
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null, 666));
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+        assertThrows(NullPointerException.class, () -> structure.setTextIdEntry(null));
+        assertThat(node.getTextIdEntry()).isNull();
+    }
+
+    @Test
+    public void testUnsupportedProperties() {
+        View view = new View(mContext);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        structure.setChildCount(1);
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        structure.addChildCount(1);
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        assertThat(structure.newChild(0)).isNull();
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        assertThat(structure.asyncNewChild(0)).isNull();
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        structure.asyncCommit();
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        structure.setWebDomain("Y U NO SET?");
+        assertThat(node.getWebDomain()).isNull();
+
+        assertThat(structure.newHtmlInfoBuilder("WHATEVER")).isNull();
+
+        structure.setHtmlInfo(mHtmlInfoMock);
+        assertThat(node.getHtmlInfo()).isNull();
+
+        structure.setDataIsSensitive(true);
+
+        assertThat(structure.getTempRect()).isNull();
+    }
+
+    @Test
+    public void testValidProperties_directly() {
+        ViewStructureImpl structure = newSimpleStructure();
+        assertSimpleStructure(structure);
+        assertSimpleNode(structure.getNode());
+    }
+
+    @Test
+    public void testValidProperties_throughParcel() {
+        ViewStructureImpl structure = newSimpleStructure();
+        final ViewNode node = structure.getNode();
+        assertSimpleNode(node); // sanity check
+
+        final ViewNode clone = cloneThroughParcel(node);
+        assertSimpleNode(clone);
+    }
+
+    @Test
+    public void testComplexText_directly() {
+        ViewStructureImpl structure = newStructureWithComplexText();
+        assertStructureWithComplexText(structure);
+        assertNodeWithComplexText(structure.getNode());
+    }
+
+    @Test
+    public void testComplexText_throughParcel() {
+        ViewStructureImpl structure = newStructureWithComplexText();
+        final ViewNode node = structure.getNode();
+        assertNodeWithComplexText(node); // sanity check
+
+        ViewNode clone = cloneThroughParcel(node);
+        assertNodeWithComplexText(clone);
+    }
+
+    @Test
+    public void testVisibility() {
+        // Visibility is a special case becase it use flag masks, so we want to make sure it works
+        // fine
+        View view = new View(mContext);
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        structure.setVisibility(View.VISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.GONE);
+        assertThat(node.getVisibility()).isEqualTo(View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+
+        structure.setVisibility(View.VISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.INVISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE);
+
+        structure.setVisibility(View.INVISIBLE | View.GONE);
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+
+
+        final int invalidValue = Math.max(Math.max(View.VISIBLE, View.INVISIBLE), View.GONE) * 2;
+        structure.setVisibility(View.VISIBLE);
+        structure.setVisibility(invalidValue); // should be ignored
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.GONE | invalidValue);
+        assertThat(node.getVisibility()).isEqualTo(View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+    }
+
+    /**
+     * Creates a {@link ViewStructureImpl} that can be asserted through
+     * {@link #assertSimpleNode(ViewNode)}.
+     */
+    private ViewStructureImpl newSimpleStructure() {
+        View view = new View(mContext);
+        view.setAutofillId(new AutofillId(42));
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+
+        // Basic properties
+        structure.setText("Text is set!");
+        structure.setClassName("Classy!");
+        structure.setContentDescription("Described I am!");
+        structure.setVisibility(View.INVISIBLE);
+
+        // Autofill properties
+        structure.setAutofillType(View.AUTOFILL_TYPE_TEXT);
+        structure.setAutofillHints(new String[] { "Auto", "Man" });
+        structure.setAutofillOptions(new String[] { "Maybe" });
+        structure.setAutofillValue(AutofillValue.forText("Malkovich"));
+
+        // Graphic properties
+        structure.setElevation(6.66f);
+        structure.setAlpha(66.6f);
+        structure.setTransformation(Matrix.IDENTITY_MATRIX);
+
+        // Extra text properties
+        structure.setMinTextEms(6);
+        structure.setMaxTextLength(66);
+        structure.setMaxTextEms(666);
+        structure.setInputType(42);
+        structure.setTextIdEntry("TEXT, Y U NO ENTRY?");
+        structure.setLocaleList(new LocaleList(Locale.US, Locale.ENGLISH));
+
+        // Resource id
+        structure.setId(16, "package.name", "type.name", "entry.name");
+
+        // Dimensions
+        structure.setDimens(4, 8, 15, 16, 23, 42);
+
+        // Boolean properties
+        structure.setAssistBlocked(true);
+        structure.setEnabled(true);
+        structure.setClickable(true);
+        structure.setLongClickable(true);
+        structure.setContextClickable(true);
+        structure.setFocusable(true);
+        structure.setFocused(true);
+        structure.setAccessibilityFocused(true);
+        structure.setChecked(true);
+        structure.setActivated(true);
+        structure.setOpaque(true);
+
+        // Bundle
+        assertThat(structure.hasExtras()).isFalse();
+        final Bundle bundle = structure.getExtras();
+        assertThat(bundle).isNotNull();
+        bundle.putString("Marlon", "Bundle");
+        assertThat(structure.hasExtras()).isTrue();
+        return structure;
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewNode} that was created by
+     * {@link #newSimpleStructure()}.
+     */
+    private void assertSimpleNode(ViewNode node) {
+
+        // Basic properties
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(42));
+        assertThat(node.getParentAutofillId()).isNull();
+        assertThat(node.getText()).isEqualTo("Text is set!");
+        assertThat(node.getClassName()).isEqualTo("Classy!");
+        assertThat(node.getContentDescription().toString()).isEqualTo("Described I am!");
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+
+        // Autofill properties
+        assertThat(node.getAutofillType()).isEqualTo(View.AUTOFILL_TYPE_TEXT);
+        assertThat(node.getAutofillHints()).asList().containsExactly("Auto", "Man").inOrder();
+        assertThat(node.getAutofillOptions()).asList().containsExactly("Maybe").inOrder();
+        assertThat(node.getAutofillValue().getTextValue()).isEqualTo("Malkovich");
+
+        // Graphic properties
+        assertThat(node.getElevation()).isWithin(1.0e-10f).of(6.66f);
+        assertThat(node.getAlpha()).isWithin(1.0e-10f).of(66.6f);
+        assertThat(node.getTransformation()).isEqualTo(Matrix.IDENTITY_MATRIX);
+
+        // Extra text properties
+        assertThat(node.getMinTextEms()).isEqualTo(6);
+        assertThat(node.getMaxTextLength()).isEqualTo(66);
+        assertThat(node.getMaxTextEms()).isEqualTo(666);
+        assertThat(node.getInputType()).isEqualTo(42);
+        assertThat(node.getTextIdEntry()).isEqualTo("TEXT, Y U NO ENTRY?");
+        assertThat(node.getLocaleList()).isEqualTo(new LocaleList(Locale.US, Locale.ENGLISH));
+
+        // Resource id
+        assertThat(node.getId()).isEqualTo(16);
+        assertThat(node.getIdPackage()).isEqualTo("package.name");
+        assertThat(node.getIdType()).isEqualTo("type.name");
+        assertThat(node.getIdEntry()).isEqualTo("entry.name");
+
+        // Dimensions
+        assertThat(node.getLeft()).isEqualTo(4);
+        assertThat(node.getTop()).isEqualTo(8);
+        assertThat(node.getScrollX()).isEqualTo(15);
+        assertThat(node.getScrollY()).isEqualTo(16);
+        assertThat(node.getWidth()).isEqualTo(23);
+        assertThat(node.getHeight()).isEqualTo(42);
+
+        // Boolean properties
+        assertThat(node.isAssistBlocked()).isTrue();
+        assertThat(node.isEnabled()).isTrue();
+        assertThat(node.isClickable()).isTrue();
+        assertThat(node.isLongClickable()).isTrue();
+        assertThat(node.isContextClickable()).isTrue();
+        assertThat(node.isFocusable()).isTrue();
+        assertThat(node.isFocused()).isTrue();
+        assertThat(node.isAccessibilityFocused()).isTrue();
+        assertThat(node.isChecked()).isTrue();
+        assertThat(node.isActivated()).isTrue();
+        assertThat(node.isOpaque()).isTrue();
+
+        // Bundle
+        final Bundle bundle = node.getExtras();
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.size()).isEqualTo(1);
+        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewStructureImpl} that was created by
+     * {@link #newSimpleStructure()}.
+     */
+    private void assertSimpleStructure(ViewStructureImpl structure) {
+        assertThat(structure.getAutofillId()).isEqualTo(new AutofillId(42));
+        assertThat(structure.getText()).isEqualTo("Text is set!");
+
+        // Bundle
+        final Bundle bundle = structure.getExtras();
+        assertThat(bundle.size()).isEqualTo(1);
+        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+    }
+
+    /**
+     * Creates a {@link ViewStructureImpl} with "complex" text properties (such as selection); it
+     * can be asserted through {@link #assertNodeWithComplexText(ViewNode)}.
+     */
+    private ViewStructureImpl newStructureWithComplexText() {
+        View view = new View(mContext);
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        structure.setText("IGNORE ME!");
+        structure.setText("Now we're talking!", 4, 8);
+        structure.setHint("Soylent Green is SPOILER ALERT");
+        structure.setTextStyle(15.0f, 16, 23, 42);
+        structure.setTextLines(new int[] {4,  8, 15} , new int[] {16, 23, 42});
+        return structure;
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewNode} that was created by
+     * {@link #newStructureWithComplexText()}.
+     */
+    private void assertNodeWithComplexText(ViewNode node) {
+        assertThat(node.getText()).isEqualTo("Now we're talking!");
+        assertThat(node.getTextSelectionStart()).isEqualTo(4);
+        assertThat(node.getTextSelectionEnd()).isEqualTo(8);
+        assertThat(node.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+        assertThat(node.getTextSize()).isWithin(1.0e-10f).of(15.0f);
+        assertThat(node.getTextColor()).isEqualTo(16);
+        assertThat(node.getTextBackgroundColor()).isEqualTo(23);
+        assertThat(node.getTextStyle()).isEqualTo(42);
+        assertThat(node.getTextLineCharOffsets()).asList().containsExactly(4, 8, 15).inOrder();
+        assertThat(node.getTextLineBaselines()).asList().containsExactly(16, 23, 42).inOrder();
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewStructureImpl} that was created by
+     * {@link #newStructureWithComplexText()}.
+     */
+    private void assertStructureWithComplexText(ViewStructureImpl structure) {
+        assertThat(structure.getText()).isEqualTo("Now we're talking!");
+        assertThat(structure.getTextSelectionStart()).isEqualTo(4);
+        assertThat(structure.getTextSelectionEnd()).isEqualTo(8);
+        assertThat(structure.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+    }
+
+    private ViewNode cloneThroughParcel(ViewNode node) {
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Write to parcel
+            parcel.setDataPosition(0); // Sanity / paranoid check
+            ViewNode.writeToParcel(parcel, node, 0);
+
+            // Read from parcel
+            parcel.setDataPosition(0);
+            ViewNode clone = ViewNode.readFromParcel(parcel);
+            assertThat(clone).isNotNull();
+            return clone;
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 80ab4ea..d161059 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -18,7 +18,7 @@
 ## The application with a minimal main dex
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex android-support-multidex-instrumentation android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex android-support-multidex-instrumentation androidx.test.rules
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
index 98d8f27..d9d9eb2 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
@@ -30,7 +30,7 @@
                      android:targetPackage="com.android.multidexlegacyandexception"
                      android:label="Test for MultiDexLegacyAndException" />
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.multidexlegacyandexception"
                      android:label="Test for MultiDexLegacyAndException" />
 </manifest>
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 92a3b0c..fae345f 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,8 +17,9 @@
 package com.android.multidexlegacyandexception.tests;
 
 import android.os.Bundle;
+
 import androidx.multidex.MultiDex;
-import android.support.test.runner.AndroidJUnitRunner;
+import androidx.test.runner.AndroidJUnitRunner;
 
 public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
index 94a5b7f..f4b02d0 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
@@ -16,7 +16,8 @@
 
 package com.android.multidexlegacyandexception.tests;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.runner.RunWith;
 
 /**
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
index f2bd353..2dc30ea 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
@@ -18,7 +18,7 @@
 ## The tests with only one dex
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation androidx.test.rules
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -41,7 +41,7 @@
 ## The tests with a minimal main dex
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation androidx.test.rules
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java
index 4e6ec14..7812c58 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java
@@ -15,10 +15,13 @@
  */
 package com.android.multidexlegacytestapp.test2;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.multidexlegacytestapp.manymethods.Big001;
 import com.android.multidexlegacytestapp.manymethods.Big079;
+
 import junit.framework.Assert;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
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 9e41a92..b3044dc 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,8 +1,9 @@
 package com.android.multidexlegacytestapp.test2;
 
 import android.os.Bundle;
+
 import androidx.multidex.MultiDex;
-import android.support.test.runner.AndroidJUnitRunner;
+import androidx.test.runner.AndroidJUnitRunner;
 
 public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 9b86b77..25f6775 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1075,6 +1075,11 @@
                 continue; // If alias and named family are conflict, use named family.
             }
             final Typeface base = systemFontMap.get(alias.getToName());
+            if (base == null) {
+                // The missing target is a valid thing, some configuration don't have font files,
+                // e.g. wear devices. Just skip this alias.
+                continue;
+            }
             final int weight = alias.getWeight();
             final Typeface newFace = weight == 400 ? base :
                     new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index b9860ad..635d0ec 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -34,7 +34,7 @@
 namespace android::uirenderer {
 
 static std::mutex sLock{};
-static ThreadBase* sUploadThread = nullptr;
+static sp<ThreadBase> sUploadThread = nullptr;
 static renderthread::EglManager sEglManager;
 static int sPendingUploads = 0;
 static nsecs_t sLastUpload = 0;
@@ -257,4 +257,15 @@
                               Bitmap::computePalette(bitmap));
 }
 
+void HardwareBitmapUploader::terminate() {
+    std::lock_guard _lock{sLock};
+    LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress");
+    if (sUploadThread) {
+        sUploadThread->requestExit();
+        sUploadThread->join();
+        sUploadThread = nullptr;
+    }
+    sEglManager.destroy();
+}
+
 }  // namespace android::uirenderer
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 6298013..40f2b0c 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -23,6 +23,7 @@
 class HardwareBitmapUploader {
 public:
     static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+    static void terminate();
 };
 
 }  // namespace android::uirenderer
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index 019950f..b2351fc 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -53,16 +53,16 @@
     VkFormat format;
 
     // Input: Color space transfer params
-    float G;
-    float A;
-    float B;
-    float C;
-    float D;
-    float E;
-    float F;
+    float g;
+    float a;
+    float b;
+    float c;
+    float d;
+    float e;
+    float f;
 
     // Input: Color space transformation from linear RGB to D50-adapted XYZ
-    float matrix[9];
+    float colorSpaceTransform[9];
 
     // Input: current clip rect
     int clipLeft;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 56eedff..8cd97ed 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -93,7 +93,9 @@
         , mHasWideColorGamutSupport(false) {}
 
 EglManager::~EglManager() {
-    destroy();
+    if (hasEglContext()) {
+        ALOGW("~EglManager() leaked an EGL context");
+    }
 }
 
 void EglManager::initialize() {
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 524dfb0..174a140 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -19,6 +19,8 @@
 
 #include "Properties.h"
 #include "hwui/Typeface.h"
+#include "HardwareBitmapUploader.h"
+#include "renderthread/RenderProxy.h"
 
 #include <benchmark/benchmark.h>
 #include <getopt.h>
@@ -353,6 +355,9 @@
         gBenchmarkReporter->Finalize();
     }
 
+    renderthread::RenderProxy::trimMemory(100);
+    HardwareBitmapUploader::terminate();
+
     LeakChecker::checkForLeaks();
     return 0;
 }
diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h
index f9de8a5..8cdcc46 100644
--- a/libs/hwui/thread/ThreadBase.h
+++ b/libs/hwui/thread/ThreadBase.h
@@ -27,7 +27,7 @@
 
 namespace android::uirenderer {
 
-class ThreadBase : protected Thread {
+class ThreadBase : public Thread {
     PREVENT_COPY_AND_ASSIGN(ThreadBase);
 
 public:
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index b9b1cdc..b4f19c9 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -39,7 +39,7 @@
     virtual ~WeakLooperCallback() { }
 
 public:
-    WeakLooperCallback(const wp<LooperCallback>& callback) :
+    explicit WeakLooperCallback(const wp<LooperCallback>& callback) :
         mCallback(callback) {
     }
 
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
index c84de4c..0b7f6e46 100644
--- a/libs/protoutil/include/android/util/EncodedBuffer.h
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -38,13 +38,13 @@
 {
 public:
     EncodedBuffer();
-    EncodedBuffer(size_t chunkSize);
+    explicit EncodedBuffer(size_t chunkSize);
     ~EncodedBuffer();
 
     class Pointer {
     public:
         Pointer();
-        Pointer(size_t chunkSize);
+        explicit Pointer(size_t chunkSize);
 
         size_t pos() const;
         size_t index() const;
@@ -161,7 +161,7 @@
     friend class iterator;
     class iterator {
     public:
-        iterator(const EncodedBuffer& buffer);
+        explicit iterator(const EncodedBuffer& buffer);
 
         /**
          * Returns the number of bytes written in the buffer
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index bdc84da..e795b81 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -89,7 +89,6 @@
     List<String> getAllProviders();
     List<String> getProviders(in Criteria criteria, boolean enabledOnly);
     String getBestProvider(in Criteria criteria, boolean enabledOnly);
-    boolean providerMeetsCriteria(String provider, in Criteria criteria);
     ProviderProperties getProviderProperties(String provider);
     String getNetworkProviderPackage();
     void setLocationControllerExtraPackage(String packageName);
@@ -98,9 +97,7 @@
     boolean isLocationControllerExtraPackageEnabled();
 
     boolean isProviderEnabledForUser(String provider, int userId);
-    boolean setProviderEnabledForUser(String provider, boolean enabled, int userId);
     boolean isLocationEnabledForUser(int userId);
-    void setLocationEnabledForUser(boolean enabled, int userId);
     void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
     void removeTestProvider(String provider, String opPackageName);
     void setTestProviderLocation(String provider, in Location loc, String opPackageName);
@@ -114,10 +111,6 @@
 
     // --- internal ---
 
-    // --- deprecated ---
-    void reportLocation(in Location location, boolean passive);
-    void reportLocationBatch(in List<Location> locations);
-
     // for reporting callback completion
     void locationCallbackFinished(ILocationListener listener);
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index d96597b..59c6a0a 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -43,6 +43,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 
 import com.android.internal.location.ProviderProperties;
@@ -1282,11 +1283,13 @@
     @SystemApi
     @RequiresPermission(WRITE_SECURE_SETTINGS)
     public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
-        try {
-            mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        Settings.Secure.putIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.LOCATION_MODE,
+                enabled
+                        ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+                        : Settings.Secure.LOCATION_MODE_OFF,
+                userHandle.getIdentifier());
     }
 
     /**
@@ -1372,20 +1375,22 @@
      * @return true if the value was set, false on database errors
      *
      * @throws IllegalArgumentException if provider is null
+     * @deprecated Do not manipulate providers individually, use
+     * {@link #setLocationEnabledForUser(boolean, UserHandle)} instead.
      * @hide
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(WRITE_SECURE_SETTINGS)
     public boolean setProviderEnabledForUser(
             String provider, boolean enabled, UserHandle userHandle) {
         checkProvider(provider);
 
-        try {
-            return mService.setProviderEnabledForUser(
-                    provider, enabled, userHandle.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return Settings.Secure.setLocationProviderEnabledForUser(
+                mContext.getContentResolver(),
+                provider,
+                enabled,
+                userHandle.getIdentifier());
     }
 
     /**
@@ -1578,7 +1583,7 @@
      */
     @Deprecated
     public void clearTestProviderEnabled(String provider) {
-        setTestProviderEnabled(provider, true);
+        setTestProviderEnabled(provider, false);
     }
 
     /**
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index b09335c..35f2877 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -18,5 +18,7 @@
     name: "com.android.location.provider",
     srcs: ["java/**/*.java"],
     api_packages: ["com.android.location.provider"],
-    metalava_enabled: false,
+    srcs_lib: "framework",
+    srcs_lib_whitelist_dirs: ["location/java"],
+    srcs_lib_whitelist_pkgs: ["com.android.internal.location"],
 }
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 1ee851f..7b20f7a 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -250,7 +250,8 @@
                     if (controllerInfo.mAllowedCommands == null) {
                         // For trusted apps, send non-null allowed commands to keep
                         // connection.
-                        controllerInfo.mAllowedCommands = new Session2CommandGroup();
+                        controllerInfo.mAllowedCommands =
+                                new Session2CommandGroup.Builder().build();
                     }
                     if (DEBUG) {
                         Log.d(TAG, "Accepting connection: " + controllerInfo);
diff --git a/media/java/android/media/Session2Command.java b/media/java/android/media/Session2Command.java
index d2a5aae..8b285f2 100644
--- a/media/java/android/media/Session2Command.java
+++ b/media/java/android/media/Session2Command.java
@@ -36,8 +36,6 @@
  * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
  * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
  * for consistent behavior across all devices.
- * </p>
- * @hide
  */
 public final class Session2Command implements Parcelable {
     /**
@@ -151,14 +149,17 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        if (dest == null) {
+            throw new IllegalArgumentException("parcel shouldn't be null");
+        }
         dest.writeInt(mCommandCode);
         dest.writeString(mCustomCommand);
         dest.writeBundle(mExtras);
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof Session2Command)) {
             return false;
         }
@@ -185,7 +186,7 @@
          * @param resultCode result code
          * @param resultData result data
          */
-        public Result(int resultCode, Bundle resultData) {
+        public Result(int resultCode, @Nullable Bundle resultData) {
             mResultCode = resultCode;
             mResultData = resultData;
         }
@@ -200,6 +201,7 @@
         /**
          * Returns the result data.
          */
+        @Nullable
         public Bundle getResultData() {
             return mResultData;
         }
diff --git a/media/java/android/media/Session2CommandGroup.java b/media/java/android/media/Session2CommandGroup.java
index 122dfb1..519888e 100644
--- a/media/java/android/media/Session2CommandGroup.java
+++ b/media/java/android/media/Session2CommandGroup.java
@@ -35,7 +35,6 @@
  * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
  * for consistent behavior across all devices.
  * </p>
- * @hide
  */
 public final class Session2CommandGroup implements Parcelable {
     private static final String TAG = "Session2CommandGroup";
@@ -56,16 +55,11 @@
     Set<Session2Command> mCommands = new HashSet<>();
 
     /**
-     * Default Constructor.
-     */
-    public Session2CommandGroup() {}
-
-    /**
      * Creates a new Session2CommandGroup with commands copied from another object.
      *
      * @param commands The collection of commands to copy.
      */
-    public Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
+    Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
         if (commands != null) {
             mCommands.addAll(commands);
         }
@@ -129,8 +123,11 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelableArray((Session2Command[]) mCommands.toArray(), 0);
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        if (dest == null) {
+            throw new IllegalArgumentException("parcel shouldn't be null");
+        }
+        dest.writeParcelableArray(mCommands.toArray(new Session2Command[0]), 0);
     }
 
     /**
@@ -149,6 +146,9 @@
          * @param commandGroup
          */
         public Builder(@NonNull Session2CommandGroup commandGroup) {
+            if (commandGroup == null) {
+                throw new IllegalArgumentException("command group shouldn't be null");
+            }
             mCommands = commandGroup.getCommands();
         }
 
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
index 4634c69..e1fff38 100644
--- a/media/java/android/media/Session2Token.java
+++ b/media/java/android/media/Session2Token.java
@@ -171,7 +171,7 @@
         dest.writeString(mPackageName);
         dest.writeString(mServiceName);
         // TODO: Uncomment below
-        //dest.writeStrongBinder(mSessionLink.asBinder());
+        //dest.writeStrongBinder(mSessionLink.getBinder());
         dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
     }
 
diff --git a/media/java/android/media/session/ControllerCallbackLink.aidl b/media/java/android/media/session/ControllerCallbackLink.aidl
new file mode 100644
index 0000000..8ee8c7d
--- /dev/null
+++ b/media/java/android/media/session/ControllerCallbackLink.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.session;
+
+parcelable ControllerCallbackLink;
diff --git a/media/java/android/media/session/ControllerCallbackLink.java b/media/java/android/media/session/ControllerCallbackLink.java
new file mode 100644
index 0000000..a143c9b
--- /dev/null
+++ b/media/java/android/media/session/ControllerCallbackLink.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.media.MediaMetadata;
+import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession.QueueItem;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * Handles incoming commands to {@link MediaController.Callback}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ */
+public final class ControllerCallbackLink implements Parcelable {
+    final CallbackStub mCallbackStub;
+    final ISessionControllerCallback mIControllerCallback;
+
+    /**
+     * Constructor for stub (Callee)
+     * @hide
+     */
+    @SystemApi
+    public ControllerCallbackLink(@NonNull CallbackStub callbackStub) {
+        mCallbackStub = callbackStub;
+        mIControllerCallback = new CallbackStubProxy();
+    }
+
+    /**
+     * Constructor for interface (Caller)
+     */
+    ControllerCallbackLink(Parcel in) {
+        mCallbackStub = null;
+        mIControllerCallback = ISessionControllerCallback.Stub.asInterface(in.readStrongBinder());
+    }
+
+    /**
+     * Notify controller that the connected session is destroyed.
+     */
+    public void notifySessionDestroyed() {
+        try {
+            mIControllerCallback.notifySessionDestroyed();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the connected session sends an event.
+     *
+     * @param event the name of the event
+     * @param extras the extras included with the event
+     */
+    public void notifyEvent(@NonNull String event, @Nullable Bundle extras) {
+        try {
+            mIControllerCallback.notifyEvent(event, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current playback state is changed.
+     *
+     * @param state the new playback state
+     */
+    public void notifyPlaybackStateChanged(@Nullable PlaybackState state) {
+        try {
+            mIControllerCallback.notifyPlaybackStateChanged(state);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current metadata is changed.
+     *
+     * @param metadata the new metadata
+     */
+    public void notifyMetadataChanged(@Nullable MediaMetadata metadata) {
+        try {
+            mIControllerCallback.notifyMetadataChanged(metadata);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current queue is changed.
+     *
+     * @param queue the new queue
+     */
+    public void notifyQueueChanged(@Nullable List<QueueItem> queue) {
+        try {
+            mIControllerCallback.notifyQueueChanged(queue);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current queue title is changed.
+     *
+     * @param title the new queue title
+     */
+    public void notifyQueueTitleChanged(@Nullable CharSequence title) {
+        try {
+            mIControllerCallback.notifyQueueTitleChanged(title);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the extras are changed.
+     *
+     * @param extras the new extras
+     */
+    public void notifyExtrasChanged(@Nullable Bundle extras) {
+        try {
+            mIControllerCallback.notifyExtrasChanged(extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the playback info is changed.
+     *
+     * @param info the new playback info
+     */
+    public void notifyVolumeInfoChanged(@NonNull PlaybackInfo info) {
+        try {
+            mIControllerCallback.notifyVolumeInfoChanged(info);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Gets the binder */
+    @NonNull
+    public IBinder getBinder() {
+        return mIControllerCallback.asBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mIControllerCallback.asBinder());
+    }
+
+    public static final Parcelable.Creator<ControllerCallbackLink> CREATOR =
+            new Parcelable.Creator<ControllerCallbackLink>() {
+        @Override
+        public ControllerCallbackLink createFromParcel(Parcel in) {
+            return new ControllerCallbackLink(in);
+        }
+
+        @Override
+        public ControllerCallbackLink[] newArray(int size) {
+            return new ControllerCallbackLink[size];
+        }
+    };
+
+    /**
+     * Class for Stub implementation
+     * @hide
+     */
+    @SystemApi
+    public abstract static class CallbackStub {
+        /** Stub method for ISessionControllerCallback.notifySessionDestroyed */
+        public void onSessionDestroyed() {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyEvent */
+        public void onEvent(@NonNull String event, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyPlaybackStateChanged */
+        public void onPlaybackStateChanged(@Nullable PlaybackState state) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyMetadataChanged */
+        public void onMetadataChanged(@Nullable MediaMetadata metadata) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyQueueChanged */
+        public void onQueueChanged(@Nullable List<QueueItem> queue) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyQueueTitleChanged */
+        public void onQueueTitleChanged(@Nullable CharSequence title) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyExtrasChanged */
+        public void onExtrasChanged(@Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyVolumeInfoChanged */
+        public void onVolumeInfoChanged(@NonNull PlaybackInfo info) {
+        }
+    }
+
+    private class CallbackStubProxy extends ISessionControllerCallback.Stub {
+        @Override
+        public void notifyEvent(String event, Bundle extras) {
+            mCallbackStub.onEvent(event, extras);
+        }
+
+        @Override
+        public void notifySessionDestroyed() {
+            mCallbackStub.onSessionDestroyed();
+        }
+
+        @Override
+        public void notifyPlaybackStateChanged(PlaybackState state) {
+            mCallbackStub.onPlaybackStateChanged(state);
+        }
+
+        @Override
+        public void notifyMetadataChanged(MediaMetadata metadata) {
+            mCallbackStub.onMetadataChanged(metadata);
+        }
+
+        @Override
+        public void notifyQueueChanged(List<QueueItem> queue) {
+            mCallbackStub.onQueueChanged(queue);
+        }
+
+        @Override
+        public void notifyQueueTitleChanged(CharSequence title) {
+            mCallbackStub.onQueueTitleChanged(title);
+        }
+
+        @Override
+        public void notifyExtrasChanged(Bundle extras) {
+            mCallbackStub.onExtrasChanged(extras);
+        }
+
+        @Override
+        public void notifyVolumeInfoChanged(PlaybackInfo info) {
+            mCallbackStub.onVolumeInfoChanged(info);
+        }
+    }
+}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index bfc05fa..1524ad9 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -16,7 +16,6 @@
 package android.media.session;
 
 import android.app.PendingIntent;
-import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
 import android.media.session.ISessionController;
@@ -41,7 +40,8 @@
     // These commands are for the TransportPerformer
     void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
     void setPlaybackState(in PlaybackState state);
-    void setQueue(in ParceledListSlice queue);
+    // TODO(b/122432476): Replace List with MediaParceledListSlice
+    void setQueue(in List<MediaSession.QueueItem> queue);
     void setQueueTitle(CharSequence title);
     void setExtras(in Bundle extras);
     void setRatingType(int type);
diff --git a/media/java/android/media/session/ISession2TokensListener.aidl b/media/java/android/media/session/ISession2TokensListener.aidl
new file mode 100644
index 0000000..7d1a4aa
--- /dev/null
+++ b/media/java/android/media/session/ISession2TokensListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.media.Session2Token;
+
+/**
+ * Listens for changes to the list of session2 tokens.
+ * @hide
+ */
+oneway interface ISession2TokensListener {
+    void onSession2TokensChanged(in List<Session2Token> tokens);
+}
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 626338d..9b86bfc 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -17,7 +17,7 @@
 
 import android.content.Intent;
 import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
+import android.media.session.ControllerCallbackLink;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
@@ -26,46 +26,46 @@
  * @hide
  */
 oneway interface ISessionCallback {
-    void onCommand(String packageName, int pid, int uid, ISessionControllerCallback caller,
+    void notifyCommand(String packageName, int pid, int uid, in ControllerCallbackLink caller,
             String command, in Bundle args, in ResultReceiver cb);
-    void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
+    void notifyMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
             int sequenceNumber, in ResultReceiver cb);
-    void onMediaButtonFromController(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, in Intent mediaButtonIntent);
+    void notifyMediaButtonFromController(String packageName, int pid, int uid,
+            in ControllerCallbackLink caller, in Intent mediaButtonIntent);
 
     // These callbacks are for the TransportPerformer
-    void onPrepare(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onPrepareFromMediaId(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, String mediaId, in Bundle extras);
-    void onPrepareFromSearch(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, String query, in Bundle extras);
-    void onPrepareFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
+    void notifyPrepare(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifyPrepareFromMediaId(String packageName, int pid, int uid,
+            in ControllerCallbackLink caller, String mediaId, in Bundle extras);
+    void notifyPrepareFromSearch(String packageName, int pid, int uid,
+            in ControllerCallbackLink caller, String query, in Bundle extras);
+    void notifyPrepareFromUri(String packageName, int pid, int uid,
+            in ControllerCallbackLink caller, in Uri uri, in Bundle extras);
+    void notifyPlay(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifyPlayFromMediaId(String packageName, int pid, int uid,
+            in ControllerCallbackLink caller, String mediaId, in Bundle extras);
+    void notifyPlayFromSearch(String packageName, int pid, int uid,
+            in ControllerCallbackLink caller, String query, in Bundle extras);
+    void notifyPlayFromUri(String packageName, int pid, int uid, in ControllerCallbackLink caller,
             in Uri uri, in Bundle extras);
-    void onPlay(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onPlayFromMediaId(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            String mediaId, in Bundle extras);
-    void onPlayFromSearch(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            String query, in Bundle extras);
-    void onPlayFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            in Uri uri, in Bundle extras);
-    void onSkipToTrack(String packageName, int pid, int uid, ISessionControllerCallback caller,
+    void notifySkipToTrack(String packageName, int pid, int uid, in ControllerCallbackLink caller,
             long id);
-    void onPause(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onStop(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onNext(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onPrevious(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onFastForward(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onRewind(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onSeekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+    void notifyPause(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifyStop(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifyNext(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifyPrevious(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifyFastForward(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifyRewind(String packageName, int pid, int uid, in ControllerCallbackLink caller);
+    void notifySeekTo(String packageName, int pid, int uid, in ControllerCallbackLink caller,
             long pos);
-    void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+    void notifyRate(String packageName, int pid, int uid, in ControllerCallbackLink caller,
             in Rating rating);
-    void onCustomAction(String packageName, int pid, int uid, ISessionControllerCallback caller,
+    void notifyCustomAction(String packageName, int pid, int uid, in ControllerCallbackLink caller,
             String action, in Bundle args);
 
     // These callbacks are for volume handling
-    void onAdjustVolume(String packageName, int pid, int uid, ISessionControllerCallback caller,
+    void notifyAdjustVolume(String packageName, int pid, int uid, in ControllerCallbackLink caller,
             int direction);
-    void onSetVolumeTo(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, int value);
+    void notifySetVolumeTo(String packageName, int pid, int uid,
+            in ControllerCallbackLink caller, int value);
 }
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index a843881..2ba09fd 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -17,10 +17,9 @@
 
 import android.app.PendingIntent;
 import android.content.Intent;
-import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
 import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
+import android.media.session.ControllerCallbackLink;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
@@ -36,12 +35,12 @@
  * @hide
  */
 interface ISessionController {
-    void sendCommand(String packageName, ISessionControllerCallback caller,
+    void sendCommand(String packageName, in ControllerCallbackLink caller,
             String command, in Bundle args, in ResultReceiver cb);
-    boolean sendMediaButton(String packageName, ISessionControllerCallback caller,
+    boolean sendMediaButton(String packageName, in ControllerCallbackLink caller,
             boolean asSystemService, in KeyEvent mediaButton);
-    void registerCallbackListener(String packageName, ISessionControllerCallback cb);
-    void unregisterCallbackListener(ISessionControllerCallback cb);
+    void registerCallbackListener(String packageName, in ControllerCallbackLink cb);
+    void unregisterCallbackListener(in ControllerCallbackLink cb);
     boolean isTransportControlEnabled();
     String getPackageName();
     String getTag();
@@ -49,40 +48,40 @@
     long getFlags();
     MediaController.PlaybackInfo getVolumeAttributes();
     void adjustVolume(String packageName, String opPackageName,
-            in ISessionControllerCallback caller, boolean asSystemService, int direction,
+            in ControllerCallbackLink caller, boolean asSystemService, int direction,
             int flags);
-    void setVolumeTo(String packageName, String opPackageName, in ISessionControllerCallback caller,
+    void setVolumeTo(String packageName, String opPackageName, in ControllerCallbackLink caller,
             int value, int flags);
 
     // These commands are for the TransportControls
-    void prepare(String packageName, ISessionControllerCallback caller);
-    void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+    void prepare(String packageName, in ControllerCallbackLink caller);
+    void prepareFromMediaId(String packageName, in ControllerCallbackLink caller,
             String mediaId, in Bundle extras);
-    void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+    void prepareFromSearch(String packageName, in ControllerCallbackLink caller,
             String string, in Bundle extras);
-    void prepareFromUri(String packageName, ISessionControllerCallback caller,
+    void prepareFromUri(String packageName, in ControllerCallbackLink caller,
             in Uri uri, in Bundle extras);
-    void play(String packageName, ISessionControllerCallback caller);
-    void playFromMediaId(String packageName, ISessionControllerCallback caller,
+    void play(String packageName, in ControllerCallbackLink caller);
+    void playFromMediaId(String packageName, in ControllerCallbackLink caller,
             String mediaId, in Bundle extras);
-    void playFromSearch(String packageName, ISessionControllerCallback caller,
+    void playFromSearch(String packageName, in ControllerCallbackLink caller,
             String string, in Bundle extras);
-    void playFromUri(String packageName, ISessionControllerCallback caller,
+    void playFromUri(String packageName, in ControllerCallbackLink caller,
             in Uri uri, in Bundle extras);
-    void skipToQueueItem(String packageName, ISessionControllerCallback caller, long id);
-    void pause(String packageName, ISessionControllerCallback caller);
-    void stop(String packageName, ISessionControllerCallback caller);
-    void next(String packageName, ISessionControllerCallback caller);
-    void previous(String packageName, ISessionControllerCallback caller);
-    void fastForward(String packageName, ISessionControllerCallback caller);
-    void rewind(String packageName, ISessionControllerCallback caller);
-    void seekTo(String packageName, ISessionControllerCallback caller, long pos);
-    void rate(String packageName, ISessionControllerCallback caller, in Rating rating);
-    void sendCustomAction(String packageName, ISessionControllerCallback caller,
+    void skipToQueueItem(String packageName, in ControllerCallbackLink caller, long id);
+    void pause(String packageName, in ControllerCallbackLink caller);
+    void stop(String packageName, in ControllerCallbackLink caller);
+    void next(String packageName, in ControllerCallbackLink caller);
+    void previous(String packageName, in ControllerCallbackLink caller);
+    void fastForward(String packageName, in ControllerCallbackLink caller);
+    void rewind(String packageName, in ControllerCallbackLink caller);
+    void seekTo(String packageName, in ControllerCallbackLink caller, long pos);
+    void rate(String packageName, in ControllerCallbackLink caller, in Rating rating);
+    void sendCustomAction(String packageName, in ControllerCallbackLink caller,
             String action, in Bundle args);
     MediaMetadata getMetadata();
     PlaybackState getPlaybackState();
-    ParceledListSlice getQueue();
+    List<MediaSession.QueueItem> getQueue();
     CharSequence getQueueTitle();
     Bundle getExtras();
     int getRatingType();
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index fac8897..5c02e7c 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -15,25 +15,24 @@
 
 package android.media.session;
 
-import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
-import android.media.session.PlaybackState;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
 import android.os.Bundle;
 
 /**
  * @hide
  */
 oneway interface ISessionControllerCallback {
-    void onEvent(String event, in Bundle extras);
-    void onSessionDestroyed();
+    void notifyEvent(String event, in Bundle extras);
+    void notifySessionDestroyed();
 
     // These callbacks are for the TransportController
-    void onPlaybackStateChanged(in PlaybackState state);
-    void onMetadataChanged(in MediaMetadata metadata);
-    void onQueueChanged(in ParceledListSlice queue);
-    void onQueueTitleChanged(CharSequence title);
-    void onExtrasChanged(in Bundle extras);
-    void onVolumeInfoChanged(in MediaController.PlaybackInfo info);
+    void notifyPlaybackStateChanged(in PlaybackState state);
+    void notifyMetadataChanged(in MediaMetadata metadata);
+    void notifyQueueChanged(in List<MediaSession.QueueItem> queue);
+    void notifyQueueTitleChanged(CharSequence title);
+    void notifyExtrasChanged(in Bundle extras);
+    void notifyVolumeInfoChanged(in MediaController.PlaybackInfo info);
 }
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 51148e2..46516e0 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -23,7 +23,8 @@
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
 import android.media.session.ISession;
-import android.media.session.ISessionCallback;
+import android.media.session.ISession2TokensListener;
+import android.media.session.SessionCallbackLink;
 import android.os.Bundle;
 import android.view.KeyEvent;
 
@@ -32,9 +33,10 @@
  * @hide
  */
 interface ISessionManager {
-    ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
+    ISession createSession(String packageName, in SessionCallbackLink cb, String tag, int userId);
     void notifySession2Created(in Session2Token sessionToken);
     List<IBinder> getSessions(in ComponentName compName, int userId);
+    List<Session2Token> getSession2Tokens(int userId);
     void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
             boolean needWakeLock);
     void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
@@ -44,6 +46,8 @@
     void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
             int userId);
     void removeSessionsListener(in IActiveSessionsListener listener);
+    void addSession2TokensListener(in ISession2TokensListener listener, int userId);
+    void removeSession2TokensListener(in ISession2TokensListener listener);
 
     // This is for the system volume UI only
     void setRemoteVolumeController(in IRemoteVolumeController rvc);
@@ -55,6 +59,5 @@
     void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
     void setOnMediaKeyListener(in IOnMediaKeyListener listener);
 
-    // MediaSession2
     boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
 }
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index ef2df15..a1b8170c 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -21,12 +21,12 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
+import android.media.session.MediaSession.QueueItem;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -72,7 +72,8 @@
 
     private final MediaSession.Token mToken;
     private final Context mContext;
-    private final CallbackStub mCbStub = new CallbackStub(this);
+    private final ControllerCallbackLink mCbStub =
+            new ControllerCallbackLink(new CallbackStub(this));
     private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
     private final Object mLock = new Object();
 
@@ -251,10 +252,7 @@
      */
     public @Nullable List<MediaSession.QueueItem> getQueue() {
         try {
-            ParceledListSlice queue = mSessionBinder.getQueue();
-            if (queue != null) {
-                return queue.getList();
-            }
+            return mSessionBinder.getQueue();
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling getQueue.", e);
         }
@@ -1113,10 +1111,10 @@
         };
     }
 
-    private final static class CallbackStub extends ISessionControllerCallback.Stub {
+    private static final class CallbackStub extends ControllerCallbackLink.CallbackStub {
         private final WeakReference<MediaController> mController;
 
-        public CallbackStub(MediaController controller) {
+        CallbackStub(MediaController controller) {
             mController = new WeakReference<MediaController>(controller);
         }
 
@@ -1153,9 +1151,7 @@
         }
 
         @Override
-        public void onQueueChanged(ParceledListSlice parceledQueue) {
-            List<MediaSession.QueueItem> queue = parceledQueue == null ? null : parceledQueue
-                    .getList();
+        public void onQueueChanged(List<QueueItem> queue) {
             MediaController controller = mController.get();
             if (controller != null) {
                 controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
@@ -1185,7 +1181,6 @@
                 controller.postMessage(MSG_UPDATE_VOLUME, info, null);
             }
         }
-
     }
 
     private final static class MessageHandler extends Handler {
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index df8cc35..e07cf15 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -24,7 +24,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
@@ -130,7 +129,7 @@
     private final MediaSession.Token mSessionToken;
     private final MediaController mController;
     private final ISession mBinder;
-    private final CallbackStub mCbStub;
+    private final SessionCallbackLink mCbStub;
 
     // Do not change the name of mCallback. Support lib accesses this by using reflection.
     @UnsupportedAppUsage
@@ -173,7 +172,7 @@
         }
         mMaxBitmapSize = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
-        mCbStub = new CallbackStub(this);
+        mCbStub = new SessionCallbackLink(new CallbackStub(this));
         MediaSessionManager manager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         try {
@@ -467,7 +466,7 @@
      */
     public void setQueue(@Nullable List<QueueItem> queue) {
         try {
-            mBinder.setQueue(queue == null ? null : new ParceledListSlice<QueueItem>(queue));
+            mBinder.setQueue(queue);
         } catch (RemoteException e) {
             Log.wtf("Dead object in setQueue.", e);
         }
@@ -1063,7 +1062,7 @@
     /**
      * @hide
      */
-    public static class CallbackStub extends ISessionCallback.Stub {
+    public static final class CallbackStub extends SessionCallbackLink.CallbackStub {
         private WeakReference<MediaSession> mMediaSession;
 
         public CallbackStub(MediaSession session) {
@@ -1071,14 +1070,14 @@
         }
 
         private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             return new RemoteUserInfo(packageName, pid, uid,
-                    caller != null ? caller.asBinder() : null);
+                    caller != null ? caller.getBinder() : null);
         }
 
         @Override
         public void onCommand(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
+                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1104,7 +1103,7 @@
 
         @Override
         public void onMediaButtonFromController(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Intent mediaButtonIntent) {
+                ControllerCallbackLink caller, Intent mediaButtonIntent) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1114,7 +1113,7 @@
 
         @Override
         public void onPrepare(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1123,7 +1122,7 @@
 
         @Override
         public void onPrepareFromMediaId(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String mediaId,
+                ControllerCallbackLink caller, String mediaId,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -1134,7 +1133,7 @@
 
         @Override
         public void onPrepareFromSearch(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String query,
+                ControllerCallbackLink caller, String query,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -1145,7 +1144,7 @@
 
         @Override
         public void onPrepareFromUri(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Uri uri, Bundle extras) {
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1155,7 +1154,7 @@
 
         @Override
         public void onPlay(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1164,7 +1163,7 @@
 
         @Override
         public void onPlayFromMediaId(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String mediaId,
+                ControllerCallbackLink caller, String mediaId,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -1175,7 +1174,7 @@
 
         @Override
         public void onPlayFromSearch(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String query,
+                ControllerCallbackLink caller, String query,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -1186,7 +1185,7 @@
 
         @Override
         public void onPlayFromUri(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Uri uri, Bundle extras) {
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1196,7 +1195,7 @@
 
         @Override
         public void onSkipToTrack(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, long id) {
+                ControllerCallbackLink caller, long id) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
@@ -1205,7 +1204,7 @@
 
         @Override
         public void onPause(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1214,7 +1213,7 @@
 
         @Override
         public void onStop(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1223,7 +1222,7 @@
 
         @Override
         public void onNext(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1232,7 +1231,7 @@
 
         @Override
         public void onPrevious(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1241,7 +1240,7 @@
 
         @Override
         public void onFastForward(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1250,7 +1249,7 @@
 
         @Override
         public void onRewind(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
@@ -1259,7 +1258,7 @@
 
         @Override
         public void onSeekTo(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, long pos) {
+                ControllerCallbackLink caller, long pos) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
@@ -1267,7 +1266,7 @@
         }
 
         @Override
-        public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+        public void onRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
                 Rating rating) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -1277,7 +1276,7 @@
 
         @Override
         public void onCustomAction(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String action, Bundle args) {
+                ControllerCallbackLink caller, String action, Bundle args) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1287,7 +1286,7 @@
 
         @Override
         public void onAdjustVolume(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, int direction) {
+                ControllerCallbackLink caller, int direction) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
@@ -1297,7 +1296,7 @@
 
         @Override
         public void onSetVolumeTo(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, int value) {
+                ControllerCallbackLink caller, int value) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index ef5cf00..4596c22 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -41,6 +41,8 @@
 import android.util.Log;
 import android.view.KeyEvent;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -69,9 +71,13 @@
      */
     public static final int RESULT_MEDIA_KEY_HANDLED = 1;
 
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
     private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
             = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
-    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final ArrayMap<OnSession2TokensChangedListener, Session2TokensChangedWrapper>
+            mSession2TokensListeners = new ArrayMap<>();
     private final ISessionManager mService;
 
     private Context mContext;
@@ -98,7 +104,7 @@
      * @return The binder object from the system
      * @hide
      */
-    public @NonNull ISession createSession(@NonNull MediaSession.CallbackStub cbStub,
+    public @NonNull ISession createSession(@NonNull SessionCallbackLink cbStub,
             @NonNull String tag, int userId) throws RemoteException {
         return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
     }
@@ -179,6 +185,44 @@
     }
 
     /**
+     * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+     * current user.
+     * <p>
+     * Although this API can be used without any restriction, each session owners can accept or
+     * reject your uses of {@link MediaSession2}.
+     *
+     * @return A list of {@link Session2Token}.
+     * @hide
+     */
+    // TODO: unhide
+    @NonNull
+    public List<Session2Token> getSession2Tokens() {
+        return getSession2Tokens(UserHandle.myUserId());
+    }
+
+    /**
+     * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+     * given user.
+     * <p>
+     * If you want to get tokens for another user, you must hold the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+     *
+     * @param userId The user id to fetch sessions for.
+     * @return A list of {@link Session2Token}
+     * @hide
+     */
+    // TODO: unhide
+    @NonNull
+    public List<Session2Token> getSession2Tokens(int userId) {
+        try {
+            return mService.getSession2Tokens(userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get session tokens", e);
+        }
+        return new ArrayList<>();
+    }
+
+    /**
      * Add a listener to be notified when the list of active sessions
      * changes.This requires the
      * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
@@ -286,6 +330,87 @@
     }
 
     /**
+     * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+     * for consistent behavior across all devices.
+     *
+     * @param listener The listener to add
+     * @param handler The handler to call listener on. If {@code null}, calling thread's looper will
+     *                be used.
+     * @hide
+     */
+    // TODO(jaewan): Unhide
+    public void addOnSession2TokensChangedListener(
+            @NonNull OnSession2TokensChangedListener listener, @Nullable Handler handler) {
+        addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, handler);
+    }
+
+    /**
+     * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+     * for consistent behavior across all devices.
+     *
+     * @param userId The userId to listen for changes on
+     * @param listener The listener to add
+     * @param handler The handler to call listener on. If {@code null}, calling thread's looper will
+     *                be used.
+     * @hide
+     */
+    public void addOnSession2TokensChangedListener(int userId,
+            @NonNull OnSession2TokensChangedListener listener, @Nullable Handler handler) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener shouldn't be null");
+        }
+        synchronized (mLock) {
+            if (mSession2TokensListeners.get(listener) != null) {
+                Log.w(TAG, "Attempted to add session listener twice, ignoring.");
+                return;
+            }
+            Session2TokensChangedWrapper wrapper =
+                    new Session2TokensChangedWrapper(listener, handler);
+            try {
+                mService.addSession2TokensListener(wrapper.getStub(), userId);
+                mSession2TokensListeners.put(listener, wrapper);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in addSessionTokensListener.", e);
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Removes the {@link OnSession2TokensChangedListener} to stop receiving session token updates.
+     *
+     * @param listener The listener to remove.
+     * @hide
+     */
+    // TODO(jaewan): Unhide
+    public void removeOnSession2TokensChangedListener(
+            @NonNull OnSession2TokensChangedListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener may not be null");
+        }
+        final Session2TokensChangedWrapper wrapper;
+        synchronized (mLock) {
+            wrapper = mSession2TokensListeners.remove(listener);
+        }
+        if (wrapper != null) {
+            try {
+                mService.removeSession2TokensListener(wrapper.getStub());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in removeSessionTokensListener.", e);
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Set the remote volume controller to receive volume updates on. Only for
      * use by system UI.
      *
@@ -552,6 +677,26 @@
     }
 
     /**
+     * Listens for changes to the {@link #getSession2Tokens()}. This can be added
+     * using {@link #addOnSession2TokensChangedListener(OnSession2TokensChangedListener, Handler)}.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+     * for consistent behavior across all devices.
+     *
+     * @hide
+     */
+    public interface OnSession2TokensChangedListener {
+        /**
+         * Called when the {@link #getSession2Tokens()} is changed.
+         *
+         * @param tokens list of {@link Session2Token}
+         */
+        void onSession2TokensChanged(@NonNull List<Session2Token> tokens);
+    }
+
+    /**
      * Listens the volume key long-presses.
      * @hide
      */
@@ -769,6 +914,27 @@
         }
     }
 
+    private static final class Session2TokensChangedWrapper {
+        private final OnSession2TokensChangedListener mListener;
+        private final Handler mHandler;
+        private final ISession2TokensListener.Stub mStub =
+                new ISession2TokensListener.Stub() {
+                    @Override
+                    public void onSession2TokensChanged(final List<Session2Token> tokens) {
+                        mHandler.post(() -> mListener.onSession2TokensChanged(tokens));
+                    }
+                };
+
+        Session2TokensChangedWrapper(OnSession2TokensChangedListener listener, Handler handler) {
+            mListener = listener;
+            mHandler = (handler == null) ? new Handler() : new Handler(handler.getLooper());
+        }
+
+        public ISession2TokensListener.Stub getStub() {
+            return mStub;
+        }
+    }
+
     private static final class OnVolumeKeyLongPressListenerImpl
             extends IOnVolumeKeyLongPressListener.Stub {
         private OnVolumeKeyLongPressListener mListener;
diff --git a/media/java/android/media/session/SessionCallbackLink.aidl b/media/java/android/media/session/SessionCallbackLink.aidl
new file mode 100644
index 0000000..c489e5b
--- /dev/null
+++ b/media/java/android/media/session/SessionCallbackLink.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.session;
+
+parcelable SessionCallbackLink;
diff --git a/media/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java
new file mode 100644
index 0000000..7547bff
--- /dev/null
+++ b/media/java/android/media/session/SessionCallbackLink.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.media.Rating;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+
+/**
+ * Handles incoming commands to {@link MediaSession.Callback}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ */
+public final class SessionCallbackLink implements Parcelable {
+    final CallbackStub mCallbackStub;
+    final ISessionCallback mISessionCallback;
+
+    /**
+     * Constructor for stub (Callee)
+     */
+    SessionCallbackLink(@NonNull CallbackStub callbackStub) {
+        mCallbackStub = callbackStub;
+        mISessionCallback = new CallbackStubProxy();
+    }
+
+    /**
+     * Constructor for interface (Caller)
+     */
+    SessionCallbackLink(Parcel in) {
+        mCallbackStub = null;
+        mISessionCallback = ISessionCallback.Stub.asInterface(in.readStrongBinder());
+    }
+
+    /**
+     * Notify session that a controller sends a command.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param command the name of the command
+     * @param args the arguments included with the command
+     * @param cb the result receiver for getting the result of the command
+     */
+    public void notifyCommand(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String command,
+            @Nullable Bundle args, @Nullable ResultReceiver cb) {
+        try {
+            mISessionCallback.notifyCommand(packageName, pid, uid, caller, command, args, cb);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that the android system sends a media button event.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param mediaButtonIntent the media button intent
+     * @param sequenceNumber the sequence number of this call
+     * @param cb the result receiver for getting the result of the command
+     */
+    public void notifyMediaButton(@NonNull String packageName, int pid, int uid,
+            @NonNull Intent mediaButtonIntent, int sequenceNumber,
+            @Nullable ResultReceiver cb) {
+        try {
+            mISessionCallback.notifyMediaButton(packageName, pid, uid, mediaButtonIntent,
+                    sequenceNumber, cb);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller sends a media button event.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaButtonIntent the media button intent
+     */
+    public void notifyMediaButtonFromController(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) {
+        try {
+            mISessionCallback.notifyMediaButtonFromController(packageName, pid, uid, caller,
+                    mediaButtonIntent);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyPrepare(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPrepare(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media from given media ID.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaId the ID of the media
+     * @param extras the extras included with this request.
+     */
+    public void notifyPrepareFromMediaId(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPrepareFromMediaId(packageName, pid, uid, caller, mediaId,
+                    extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media from given search query.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param query the search query
+     * @param extras the extras included with this request.
+     */
+    public void notifyPrepareFromSearch(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String query,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media from given uri.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param uri the uri of the media
+     * @param extras the extras included with this request.
+     */
+    public void notifyPrepareFromUri(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyPlay(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPlay(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media from given media ID.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaId the ID of the media
+     * @param extras the extras included with this request.
+     */
+    public void notifyPlayFromMediaId(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media from given search query.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param query the search query
+     * @param extras the extras included with this request.
+     */
+    public void notifyPlayFromSearch(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String query,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPlayFromSearch(packageName, pid, uid, caller, query, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media from given uri.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param uri the uri of the media
+     * @param extras the extras included with this request.
+     */
+    public void notifyPlayFromUri(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPlayFromUri(packageName, pid, uid, caller, uri, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests skipping to the queue item with given ID.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param id the queue id of the item
+     */
+    public void notifySkipToTrack(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, long id) {
+        try {
+            mISessionCallback.notifySkipToTrack(packageName, pid, uid, caller, id);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests pausing media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyPause(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPause(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests stopping media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyStop(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyStop(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests skipping to the next queue item.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyNext(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyNext(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests skipping to the previous queue item.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyPrevious(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPrevious(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests fast-forwarding.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyFastForward(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyFastForward(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests rewinding.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    public void notifyRewind(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyRewind(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests seeking to the specific position.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param pos the position to move to, in milliseconds
+     */
+    public void notifySeekTo(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, long pos) {
+        try {
+            mISessionCallback.notifySeekTo(packageName, pid, uid, caller, pos);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests rating of the current media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param rating the rating of the current media
+     */
+    public void notifyRate(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Rating rating) {
+        try {
+            mISessionCallback.notifyRate(packageName, pid, uid, caller, rating);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller sends a custom action.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param action the name of the action
+     * @param args the arguments included with this action
+     */
+    public void notifyCustomAction(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String action, @Nullable Bundle args) {
+        try {
+            mISessionCallback.notifyCustomAction(packageName, pid, uid, caller, action, args);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests adjusting volume.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param direction the direction of the volume change.
+     */
+    public void notifyAdjustVolume(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, int direction) {
+        try {
+            mISessionCallback.notifyAdjustVolume(packageName, pid, uid, caller, direction);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests setting volume.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param value the volume value to set
+     */
+    public void notifySetVolumeTo(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, int value) {
+        try {
+            mISessionCallback.notifySetVolumeTo(packageName, pid, uid, caller, value);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Gets the binder */
+    @NonNull
+    public IBinder getBinder() {
+        return mISessionCallback.asBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mISessionCallback.asBinder());
+    }
+
+    public static final Parcelable.Creator<SessionCallbackLink> CREATOR =
+            new Parcelable.Creator<SessionCallbackLink>() {
+                @Override
+                public SessionCallbackLink createFromParcel(Parcel in) {
+                    return new SessionCallbackLink(in);
+                }
+
+                @Override
+                public SessionCallbackLink[] newArray(int size) {
+                    return new SessionCallbackLink[size];
+                }
+            };
+
+    /**
+     * Class for Stub implementation
+     */
+    abstract static class CallbackStub {
+        /** Stub method for ISessionCallback.notifyCommand */
+        public void onCommand(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String command,
+                @Nullable Bundle args, @Nullable ResultReceiver cb) {
+        }
+
+        /** Stub method for ISessionCallback.notifyMediaButton */
+        public void onMediaButton(@NonNull String packageName, int pid, int uid,
+                @NonNull Intent mediaButtonIntent, int sequenceNumber,
+                @Nullable ResultReceiver cb) {
+        }
+
+        /** Stub method for ISessionCallback.notifyMediaButtonFromController */
+        public void onMediaButtonFromController(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepare */
+        public void onPrepare(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepareFromMediaId */
+        public void onPrepareFromMediaId(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepareFromSearch */
+        public void onPrepareFromSearch(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepareFromUri */
+        public void onPrepareFromUri(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlay */
+        public void onPlay(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlayFromMediaId */
+        public void onPlayFromMediaId(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlayFromSearch */
+        public void onPlayFromSearch(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlayFromUri */
+        public void onPlayFromUri(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifySkipToTrack */
+        public void onSkipToTrack(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, long id) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPause */
+        public void onPause(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyStop */
+        public void onStop(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyNext */
+        public void onNext(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrevious */
+        public void onPrevious(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyFastForward */
+        public void onFastForward(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyRewind */
+        public void onRewind(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifySeekTo */
+        public void onSeekTo(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, long pos) {
+        }
+
+        /** Stub method for ISessionCallback.notifyRate */
+        public void onRate(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Rating rating) {
+        }
+
+        /** Stub method for ISessionCallback.notifyCustomAction */
+        public void onCustomAction(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String action,
+                @Nullable Bundle args) {
+        }
+
+        /** Stub method for ISessionCallback.notifyAdjustVolume */
+        public void onAdjustVolume(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, int direction) {
+        }
+
+        /** Stub method for ISessionCallback.notifySetVolumeTo */
+        public void onSetVolumeTo(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, int value) {
+        }
+    }
+
+    private class CallbackStubProxy extends ISessionCallback.Stub {
+        @Override
+        public void notifyCommand(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
+            mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb);
+        }
+
+        @Override
+        public void notifyMediaButton(String packageName, int pid, int uid,
+                Intent mediaButtonIntent, int sequenceNumber, ResultReceiver cb) {
+            mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceNumber,
+                    cb);
+        }
+
+        @Override
+        public void notifyMediaButtonFromController(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Intent mediaButtonIntent) {
+            mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller,
+                    mediaButtonIntent);
+        }
+
+        @Override
+        public void notifyPrepare(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onPrepare(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifyPrepareFromMediaId(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String mediaId, Bundle extras) {
+            mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+        }
+
+        @Override
+        public void notifyPrepareFromSearch(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String query, Bundle extras) {
+            mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+        }
+
+        @Override
+        public void notifyPrepareFromUri(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
+            mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+        }
+
+        @Override
+        public void notifyPlay(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onPlay(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifyPlayFromMediaId(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String mediaId, Bundle extras) {
+            mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+        }
+
+        @Override
+        public void notifyPlayFromSearch(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String query, Bundle extras) {
+            mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
+        }
+
+        @Override
+        public void notifyPlayFromUri(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
+            mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
+        }
+
+        @Override
+        public void notifySkipToTrack(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, long id) {
+            mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id);
+        }
+
+        @Override
+        public void notifyPause(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onPause(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifyStop(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onStop(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifyNext(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onNext(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifyPrevious(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onPrevious(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifyFastForward(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onFastForward(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifyRewind(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            mCallbackStub.onRewind(packageName, pid, uid, caller);
+        }
+
+        @Override
+        public void notifySeekTo(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, long pos) {
+            mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos);
+        }
+
+        @Override
+        public void notifyRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
+                Rating rating) {
+            mCallbackStub.onRate(packageName, pid, uid, caller, rating);
+        }
+
+        @Override
+        public void notifyCustomAction(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String action, Bundle args) {
+            mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args);
+        }
+
+        @Override
+        public void notifyAdjustVolume(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, int direction) {
+            mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction);
+        }
+
+        @Override
+        public void notifySetVolumeTo(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, int value) {
+            mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value);
+        }
+    }
+}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index fa69062..ada77c5 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -372,6 +372,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+    @UnsupportedAppUsage
     public int getModelState(UUID soundModelId) {
         if (soundModelId == null) {
             return STATUS_ERROR;
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 8c43683..44f8725 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -18,5 +18,7 @@
     name: "com.android.mediadrm.signer",
     srcs: ["java/**/*.java"],
     api_packages: ["com.android.mediadrm.signer"],
-    metalava_enabled: false,
+    srcs_lib: "framework",
+    srcs_lib_whitelist_dirs: ["media/java"],
+    srcs_lib_whitelist_pkgs: ["android.media"],
 }
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 5cfb09b..fdcfc44 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -83,6 +83,10 @@
     include_dirs: ["bionic/libc/dns/include"],
 
     version_script: "libandroid.map.txt",
+    stubs: {
+        symbol_file: "libandroid.map.txt",
+        versions: ["29"],
+    },
 }
 
 // Network library.
diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp
index 0936256..88decc8 100644
--- a/native/webview/plat_support/Android.bp
+++ b/native/webview/plat_support/Android.bp
@@ -24,7 +24,6 @@
     srcs: [
         "draw_functor.cpp",
         "draw_gl_functor.cpp",
-        "draw_vk_functor.cpp",
         "functor_utils.cpp",
         "jni_entry_point.cpp",
         "graphics_utils.cpp",
diff --git a/native/webview/plat_support/draw_vk.h b/native/webview/plat_support/draw_vk.h
deleted file mode 100644
index 6b7d8d0..0000000
--- a/native/webview/plat_support/draw_vk.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-//******************************************************************************
-// This is a copy of the coresponding android_webview/public/browser header.
-// Any changes to the interface should be made there.
-//
-// The purpose of having the copy is twofold:
-//  - it removes the need to have Chromium sources present in the tree in order
-//    to build the plat_support library,
-//  - it captures API that the corresponding Android release supports.
-//******************************************************************************
-
-#ifndef ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
-#define ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
-
-#include <vulkan/vulkan.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static const int kAwDrawVKInfoVersion = 1;
-
-// Holds the information required to trigger initialization of the Vulkan
-// functor.
-struct InitParams {
-  // All params are input
-  VkInstance instance;
-  VkPhysicalDevice physical_device;
-  VkDevice device;
-  VkQueue queue;
-  uint32_t graphics_queue_index;
-  uint32_t instance_version;
-  const char* const* enabled_extension_names;
-  // Only one of device_features and device_features_2 should be non-null.
-  // If both are null then no features are enabled.
-  VkPhysicalDeviceFeatures* device_features;
-  VkPhysicalDeviceFeatures2* device_features_2;
-};
-
-// Holds the information required to trigger an Vulkan composite operation.
-struct CompositeParams {
-  // Input: current width/height of destination surface.
-  int width;
-  int height;
-
-  // Input: is the render target a FBO
-  bool is_layer;
-
-  // Input: current transform matrix
-  float transform[16];
-
-  // Input WebView should do its main compositing draws into this. It cannot do
-  // anything that would require stopping the render pass.
-  VkCommandBuffer secondary_command_buffer;
-
-  // Input: The main color attachment index where secondary_command_buffer will
-  // eventually be submitted.
-  uint32_t color_attachment_index;
-
-  // Input: A render pass which will be compatible to the one which the
-  // secondary_command_buffer will be submitted into.
-  VkRenderPass compatible_render_pass;
-
-  // Input: Format of the destination surface.
-  VkFormat format;
-
-  // Input: Color space transfer params
-  float G;
-  float A;
-  float B;
-  float C;
-  float D;
-  float E;
-  float F;
-
-  // Input: Color space transformation from linear RGB to D50-adapted XYZ
-  float matrix[9];
-
-  // Input: current clip rect
-  int clip_left;
-  int clip_top;
-  int clip_right;
-  int clip_bottom;
-};
-
-// Holds the information for the post-submission callback of main composite
-// draw.
-struct PostCompositeParams {
-  // Input: Fence for the composite command buffer to signal it has finished its
-  // work on the GPU.
-  int fd;
-};
-
-// Holds the information required to trigger an Vulkan operation.
-struct AwDrawVKInfo {
-  int version;  // The AwDrawVKInfo this struct was built with.
-
-  // Input: tells the draw function what action to perform.
-  enum Mode {
-    kModeInit = 0,
-    kModeReInit = 1,
-    kModePreComposite = 2,
-    kModeComposite = 3,
-    kModePostComposite = 4,
-    kModeSync = 5,
-  } mode;
-
-  // Input: The parameters for the functor being called
-  union ParamUnion {
-    struct InitParams init_params;
-    struct CompositeParams composite_params;
-    struct PostCompositeParams post_composite_params;
-  } info;
-};
-
-typedef void(AwDrawVKFunction)(long view_context, AwDrawVKInfo* draw_info);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
diff --git a/native/webview/plat_support/draw_vk_functor.cpp b/native/webview/plat_support/draw_vk_functor.cpp
deleted file mode 100644
index eab1340..0000000
--- a/native/webview/plat_support/draw_vk_functor.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.
- */
-
-// Provides a webviewchromium glue layer adapter from the internal Android
-// Vulkan Functor data types into the types the chromium stack expects, and
-// back.
-
-#define LOG_TAG "webviewchromium_plat_support"
-
-#include "draw_fn.h"
-#include "draw_vk.h"
-
-#include <jni.h>
-#include <private/hwui/DrawVkInfo.h>
-#include <utils/Functor.h>
-#include <utils/Log.h>
-
-#include "functor_utils.h"
-
-#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
-
-namespace android {
-namespace {
-
-AwDrawVKFunction* g_aw_drawvk_function = NULL;
-
-class DrawVKFunctor : public Functor {
- public:
-  explicit DrawVKFunctor(jlong view_context) : view_context_(view_context) {}
-  ~DrawVKFunctor() override {}
-
-  // Functor
-  status_t operator ()(int what, void* data) override {
-    using uirenderer::DrawVkInfo;
-    if (!g_aw_drawvk_function) {
-      ALOGE("Cannot draw: no DrawVK Function installed");
-      return DrawVkInfo::kStatusDone;
-    }
-
-    AwDrawVKInfo aw_info;
-    aw_info.version = kAwDrawVKInfoVersion;
-    switch (what) {
-      case DrawVkInfo::kModeComposite: {
-        aw_info.mode = AwDrawVKInfo::kModeComposite;
-        DrawVkInfo* vk_info = reinterpret_cast<DrawVkInfo*>(data);
-
-        // Map across the input values.
-        CompositeParams& params = aw_info.info.composite_params;
-        params.width = vk_info->width;
-        params.height = vk_info->height;
-        params.is_layer = vk_info->isLayer;
-        for (size_t i = 0; i < 16; i++) {
-            params.transform[i] = vk_info->transform[i];
-        }
-        params.secondary_command_buffer = vk_info->secondaryCommandBuffer;
-        params.color_attachment_index = vk_info->colorAttachmentIndex;
-        params.compatible_render_pass = vk_info->compatibleRenderPass;
-        params.format = vk_info->format;
-        params.G = vk_info->G;
-        params.A = vk_info->A;
-        params.B = vk_info->B;
-        params.C = vk_info->C;
-        params.D = vk_info->D;
-        params.E = vk_info->E;
-        params.F = vk_info->F;
-        for (size_t i = 0; i < 9; i++) {
-            params.matrix[i] = vk_info->matrix[i];
-        }
-        params.clip_left = vk_info->clipLeft;
-        params.clip_top = vk_info->clipTop;
-        params.clip_right = vk_info->clipRight;
-        params.clip_bottom = vk_info->clipBottom;
-
-        break;
-      }
-      case DrawVkInfo::kModePostComposite:
-        break;
-      case DrawVkInfo::kModeSync:
-        aw_info.mode = AwDrawVKInfo::kModeSync;
-        break;
-      default:
-        ALOGE("Unexpected DrawVKInfo type %d", what);
-        return DrawVkInfo::kStatusDone;
-    }
-
-    // Invoke the DrawVK method.
-    g_aw_drawvk_function(view_context_, &aw_info);
-
-    return DrawVkInfo::kStatusDone;
-  }
-
- private:
-  intptr_t view_context_;
-};
-
-jlong CreateVKFunctor(JNIEnv*, jclass, jlong view_context) {
-  RaiseFileNumberLimit();
-  return reinterpret_cast<jlong>(new DrawVKFunctor(view_context));
-}
-
-void DestroyVKFunctor(JNIEnv*, jclass, jlong functor) {
-  delete reinterpret_cast<DrawVKFunctor*>(functor);
-}
-
-void SetChromiumAwDrawVKFunction(JNIEnv*, jclass, jlong draw_function) {
-  g_aw_drawvk_function = reinterpret_cast<AwDrawVKFunction*>(draw_function);
-}
-
-const char kClassName[] = "com/android/webview/chromium/DrawVKFunctor";
-const JNINativeMethod kJniMethods[] = {
-    { "nativeCreateVKFunctor", "(J)J",
-        reinterpret_cast<void*>(CreateVKFunctor) },
-    { "nativeDestroyVKFunctor", "(J)V",
-        reinterpret_cast<void*>(DestroyVKFunctor) },
-    { "nativeSetChromiumAwDrawVKFunction", "(J)V",
-        reinterpret_cast<void*>(SetChromiumAwDrawVKFunction) },
-};
-
-}  // namespace
-
-void RegisterDrawVKFunctor(JNIEnv* env) {
-  jclass clazz = env->FindClass(kClassName);
-  LOG_ALWAYS_FATAL_IF(!clazz, "Unable to find class '%s'", kClassName);
-
-  int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods));
-  LOG_ALWAYS_FATAL_IF(res < 0, "register native methods failed: res=%d", res);
-}
-
-}  // namespace android
diff --git a/packages/AppPredictionLib/Android.bp b/packages/AppPredictionLib/Android.bp
new file mode 100644
index 0000000..e0f4ded
--- /dev/null
+++ b/packages/AppPredictionLib/Android.bp
@@ -0,0 +1,24 @@
+// 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.
+
+android_library {
+    name: "app_prediction",
+
+    sdk_version: "system_current",
+    min_sdk_version: "system_current",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+}
diff --git a/packages/AppPredictionLib/AndroidManifest.xml b/packages/AppPredictionLib/AndroidManifest.xml
new file mode 100644
index 0000000..b992788
--- /dev/null
+++ b/packages/AppPredictionLib/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?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.app.prediction">
+</manifest>
diff --git a/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java b/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java
new file mode 100644
index 0000000..0993c9a
--- /dev/null
+++ b/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java
@@ -0,0 +1,71 @@
+/*
+ * 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.app.prediction;
+
+/**
+ * Constants to be used with {@link android.app.prediction.AppPredictor}.
+ */
+public class Constants {
+
+    /**
+     * UI surface for predictions displayed on the user's home screen
+     */
+    public static final String UI_SURFACE_HOME = "home";
+
+    /**
+     * UI surface for predictions displayed on the recents/task switcher view
+     */
+    public static final String UI_SURFACE_RECENTS = "recents";
+
+    /**
+     * UI surface for predictions displayed on the share sheet.
+     */
+    public static final String UI_SURFACE_SHARE = "share";
+
+    /**
+     * Location constant when an app target or shortcut is started from the apps list
+     */
+    public static final String LAUNCH_LOCATION_APPS_LIST = "apps_list";
+
+    /**
+     * Location constant when an app target or shortcut is started from the user's home screen
+     */
+    public static final String LAUNCH_LOCATION_APPS_HOME = "home";
+
+    /**
+     * Location constant when an app target or shortcut is started from task switcher
+     */
+    public static final String LAUNCH_LOCATION_APPS_RECENTS = "recents";
+
+    /**
+     * Location constant when an app target or shortcut is started in the share sheet while it is
+     * in collapsed state (showing a limited set of result).
+     */
+    public static final String LAUNCH_LOCATION_APPS_SHARE_COLLAPSED = "share_collapsed";
+
+    /**
+     * Location constant when an app target or shortcut is started in the share sheet while it is
+     * in expended state and showing all the results.
+     */
+    public static final String LAUNCH_LOCATION_APPS_SHARE_EXPANDED = "shared_expanded";
+
+    /**
+     * Location constant when an app target or shortcut is started in the share sheet when the
+     * target is displayed as a placeholder for an deprecated object.
+     */
+    public static final String LAUNCH_LOCATION_APPS_SHARE_LEGACY = "share_legacy";
+}
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.mk b/packages/CarrierDefaultApp/tests/unit/Android.mk
index 8e3785e..4c638811 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.mk
+++ b/packages/CarrierDefaultApp/tests/unit/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules mockito-target-minus-junit4
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml b/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
index 3a06a09..7a26d95 100644
--- a/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
@@ -21,7 +21,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.carrierdefaultapp"
         android:label="CarrierDefaultApp Unit Test Cases">
     </instrumentation>
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index fab1bcc..838b88b 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -382,11 +382,11 @@
     }
 
     @Override
-    public void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+    public void onActionInvoked(@NonNull String key, @NonNull Notification.Action action,
             @Source int source) {
         if (DEBUG) {
             Log.d(TAG,
-                    "onActionClicked() called with: key = [" + key + "], action = [" + action.title
+                    "onActionInvoked() called with: key = [" + key + "], action = [" + action.title
                             + "], source = [" + source + "]");
         }
         mSmartActionsHelper.onActionClicked(key, action, source);
diff --git a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
index 71fd9ce..acf1180 100644
--- a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
+++ b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
@@ -27,7 +27,9 @@
 import android.app.NotificationChannel;
 import android.app.Person;
 import android.app.RemoteInput;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.media.AudioAttributes;
 import android.media.AudioSystem;
 import android.os.Build;
@@ -67,8 +69,12 @@
 
     private boolean isPreChannelsNotification() {
         try {
-            mTargetSdkVersion = mPackageManager.getApplicationInfo(
-                    mSbn.getPackageName(), 0, mSbn.getUserId()).targetSdkVersion;
+            ApplicationInfo info = mPackageManager.getApplicationInfo(
+                    mSbn.getPackageName(), PackageManager.MATCH_ALL,
+                    mSbn.getUserId());
+            if (info != null) {
+                mTargetSdkVersion = info.targetSdkVersion;
+            }
         } catch (RemoteException e) {
             Log.w(TAG, "Couldn't look up " + mSbn.getPackageName());
         }
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 4688848..2f7d599 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -21,10 +21,10 @@
     installable: true,
     srcs: [
         "src/**/*.java",
+        ":services-networkstack-shared-srcs",
     ],
     static_libs: [
         "dhcp-packet-lib",
-        "frameworks-net-shared-utils",
     ]
 }
 
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 8516d94..0b0f1ec 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -22,8 +22,11 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <!-- Launch captive portal app as specific user -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.NETWORK_STACK" />
     <application
         android:label="NetworkStack"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/NetworkStack/src/android/net/util/SharedLog.java b/packages/NetworkStack/src/android/net/util/SharedLog.java
index 74bc147..4fabf10 100644
--- a/packages/NetworkStack/src/android/net/util/SharedLog.java
+++ b/packages/NetworkStack/src/android/net/util/SharedLog.java
@@ -69,6 +69,10 @@
         mComponent = component;
     }
 
+    public String getTag() {
+        return mTag;
+    }
+
     /**
      * Create a SharedLog based on this log with an additional component prefix on each logged line.
      */
diff --git a/services/net/java/android/net/util/Stopwatch.java b/packages/NetworkStack/src/android/net/util/Stopwatch.java
similarity index 78%
rename from services/net/java/android/net/util/Stopwatch.java
rename to packages/NetworkStack/src/android/net/util/Stopwatch.java
index cb15ee5..c316699 100644
--- a/services/net/java/android/net/util/Stopwatch.java
+++ b/packages/NetworkStack/src/android/net/util/Stopwatch.java
@@ -38,9 +38,9 @@
         return (isStarted() && !isStopped());
     }
 
-    // Returning |this| makes possible the following usage pattern:
-    //
-    //     Stopwatch s = new Stopwatch().start();
+    /**
+     * Start the Stopwatch.
+     */
     public Stopwatch start() {
         if (!isStarted()) {
             mStartTimeMs = SystemClock.elapsedRealtime();
@@ -48,7 +48,10 @@
         return this;
     }
 
-    // Returns the total time recorded, in milliseconds, or 0 if not started.
+    /**
+     * Stop the Stopwatch.
+     * @return the total time recorded, in milliseconds, or 0 if not started.
+     */
     public long stop() {
         if (isRunning()) {
             mStopTimeMs = SystemClock.elapsedRealtime();
@@ -57,9 +60,11 @@
         return (mStopTimeMs - mStartTimeMs);
     }
 
-    // Returns the total time recorded to date, in milliseconds.
-    // If the Stopwatch is not running, returns the same value as stop(),
-    // i.e. either the total time recorded before stopping or 0.
+    /**
+     * Return the total time recorded to date, in milliseconds.
+     * If the Stopwatch is not running, returns the same value as stop(),
+     * i.e. either the total time recorded before stopping or 0.
+     */
     public long lap() {
         if (isRunning()) {
             return (SystemClock.elapsedRealtime() - mStartTimeMs);
@@ -68,6 +73,9 @@
         }
     }
 
+    /**
+     * Reset the Stopwatch. It will be stopped when this method returns.
+     */
     public void reset() {
         mStartTimeMs = 0;
         mStopTimeMs = 0;
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 7fea1e0..057012d 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -25,18 +25,31 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkStackConnector;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.PrivateDnsConfigParcel;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServerCallbacks;
+import android.net.shared.PrivateDnsConfig;
 import android.net.util.SharedLog;
 import android.os.IBinder;
 import android.os.RemoteException;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.connectivity.NetworkMonitor;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 
 /**
  * Android service used to start the network stack when bound to via an intent.
@@ -52,17 +65,41 @@
      * <p>On platforms where the network stack runs in the system server process, this method may
      * be called directly instead of obtaining the connector by binding to the service.
      */
-    public static IBinder makeConnector() {
-        return new NetworkStackConnector();
+    public static IBinder makeConnector(Context context) {
+        return new NetworkStackConnector(context);
     }
 
     @NonNull
     @Override
     public IBinder onBind(Intent intent) {
-        return makeConnector();
+        return makeConnector(this);
     }
 
     private static class NetworkStackConnector extends INetworkStackConnector.Stub {
+        private static final int NUM_VALIDATION_LOG_LINES = 20;
+        private final Context mContext;
+        private final ConnectivityManager mCm;
+
+        private static final int MAX_VALIDATION_LOGS = 10;
+        @GuardedBy("mValidationLogs")
+        private final ArrayDeque<SharedLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
+
+        private SharedLog addValidationLogs(Network network, String name) {
+            final SharedLog log = new SharedLog(NUM_VALIDATION_LOG_LINES, network + " - " + name);
+            synchronized (mValidationLogs) {
+                while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
+                    mValidationLogs.removeLast();
+                }
+                mValidationLogs.addFirst(log);
+            }
+            return log;
+        }
+
+        NetworkStackConnector(Context context) {
+            mContext = context;
+            mCm = context.getSystemService(ConnectivityManager.class);
+        }
+
         @NonNull
         private final SharedLog mLog = new SharedLog(TAG);
 
@@ -89,11 +126,102 @@
         }
 
         @Override
+        public void makeNetworkMonitor(int netId, String name, INetworkMonitorCallbacks cb)
+                throws RemoteException {
+            final Network network = new Network(netId, false /* privateDnsBypass */);
+            final NetworkRequest defaultRequest = mCm.getDefaultRequest();
+            final SharedLog log = addValidationLogs(network, name);
+            final NetworkMonitor nm = new NetworkMonitor(
+                    mContext, cb, network, defaultRequest, log);
+            cb.onNetworkMonitorCreated(new NetworkMonitorImpl(nm));
+        }
+
+        @Override
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                 @Nullable String[] args) {
             checkNetworkStackCallingPermission();
-            fout.println("NetworkStack logs:");
-            mLog.dump(fd, fout, args);
+            final IndentingPrintWriter pw = new IndentingPrintWriter(fout, "  ");
+            pw.println("NetworkStack logs:");
+            mLog.dump(fd, pw, args);
+
+            pw.println();
+            pw.println("Validation logs (most recent first):");
+            synchronized (mValidationLogs) {
+                for (SharedLog p : mValidationLogs) {
+                    pw.println(p.getTag());
+                    pw.increaseIndent();
+                    p.dump(fd, pw, args);
+                    pw.decreaseIndent();
+                }
+            }
+        }
+    }
+
+    private static class NetworkMonitorImpl extends INetworkMonitor.Stub {
+        private final NetworkMonitor mNm;
+
+        NetworkMonitorImpl(NetworkMonitor nm) {
+            mNm = nm;
+        }
+
+        @Override
+        public void start() {
+            checkNetworkStackCallingPermission();
+            mNm.start();
+        }
+
+        @Override
+        public void launchCaptivePortalApp() {
+            checkNetworkStackCallingPermission();
+            mNm.launchCaptivePortalApp();
+        }
+
+        @Override
+        public void forceReevaluation(int uid) {
+            checkNetworkStackCallingPermission();
+            mNm.forceReevaluation(uid);
+        }
+
+        @Override
+        public void notifyPrivateDnsChanged(PrivateDnsConfigParcel config) {
+            checkNetworkStackCallingPermission();
+            mNm.notifyPrivateDnsSettingsChanged(PrivateDnsConfig.fromParcel(config));
+        }
+
+        @Override
+        public void notifyDnsResponse(int returnCode) {
+            checkNetworkStackCallingPermission();
+            mNm.notifyDnsResponse(returnCode);
+        }
+
+        @Override
+        public void notifySystemReady() {
+            checkNetworkStackCallingPermission();
+            mNm.notifySystemReady();
+        }
+
+        @Override
+        public void notifyNetworkConnected() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyNetworkConnected();
+        }
+
+        @Override
+        public void notifyNetworkDisconnected() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyNetworkDisconnected();
+        }
+
+        @Override
+        public void notifyLinkPropertiesChanged() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyLinkPropertiesChanged();
+        }
+
+        @Override
+        public void notifyNetworkCapabilitiesChanged() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyNetworkCapabilitiesChanged();
         }
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
similarity index 84%
rename from services/core/java/com/android/server/connectivity/NetworkMonitor.java
rename to packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 2a00025..94ea1b9 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -21,6 +21,11 @@
 import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
 import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
 import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
 import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
 import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
@@ -35,6 +40,9 @@
 import android.net.CaptivePortal;
 import android.net.ConnectivityManager;
 import android.net.ICaptivePortal;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
@@ -46,11 +54,14 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.metrics.ValidationProbeEvent;
+import android.net.shared.NetworkMonitorUtils;
+import android.net.shared.PrivateDnsConfig;
+import android.net.util.SharedLog;
 import android.net.util.Stopwatch;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.os.Handler;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -65,8 +76,6 @@
 import android.telephony.CellInfoWcdma;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.LocalLog.ReadOnlyLocalLog;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -75,7 +84,6 @@
 import com.android.internal.util.RingBufferIndices;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
@@ -104,9 +112,7 @@
     // Default configuration values for captive portal detection probes.
     // TODO: append a random length parameter to the default HTTPS url.
     // TODO: randomize browser version ids in the default User-Agent String.
-    private static final String DEFAULT_HTTPS_URL     = "https://www.google.com/generate_204";
-    private static final String DEFAULT_HTTP_URL      =
-            "http://connectivitycheck.gstatic.com/generate_204";
+    private static final String DEFAULT_HTTPS_URL = "https://www.google.com/generate_204";
     private static final String DEFAULT_FALLBACK_URL  = "http://www.google.com/gen_204";
     private static final String DEFAULT_OTHER_FALLBACK_URLS =
             "http://play.googleapis.com/generate_204";
@@ -144,33 +150,12 @@
         }
     }
 
-    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
-    // The network should be used as a default internet connection.  It was found to be:
-    // 1. a functioning network providing internet access, or
-    // 2. a captive portal and the user decided to use it as is.
-    public static final int NETWORK_TEST_RESULT_VALID = 0;
-    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
-    // The network should not be used as a default internet connection.  It was found to be:
-    // 1. a captive portal and the user is prompted to sign-in, or
-    // 2. a captive portal and the user did not want to use it, or
-    // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed).
-    public static final int NETWORK_TEST_RESULT_INVALID = 1;
-
     private static final int BASE = Protocol.BASE_NETWORK_MONITOR;
-
     /**
-     * Inform NetworkMonitor that their network is connected.
+     * ConnectivityService has sent a notification to indicate that network has connected.
      * Initiates Network Validation.
      */
-    public static final int CMD_NETWORK_CONNECTED = BASE + 1;
-
-    /**
-     * Inform ConnectivityService that the network has been tested.
-     * obj = String representing URL that Internet probe was redirect to, if it was redirected.
-     * arg1 = One of the NETWORK_TESTED_RESULT_* constants.
-     * arg2 = NetID.
-     */
-    public static final int EVENT_NETWORK_TESTED = BASE + 2;
+    private static final int CMD_NETWORK_CONNECTED = BASE + 1;
 
     /**
      * Message to self indicating it's time to evaluate a network's connectivity.
@@ -179,9 +164,9 @@
     private static final int CMD_REEVALUATE = BASE + 6;
 
     /**
-     * Inform NetworkMonitor that the network has disconnected.
+     * ConnectivityService has sent a notification to indicate that network has disconnected.
      */
-    public static final int CMD_NETWORK_DISCONNECTED = BASE + 7;
+    private static final int CMD_NETWORK_DISCONNECTED = BASE + 7;
 
     /**
      * Force evaluation even if it has succeeded in the past.
@@ -199,21 +184,13 @@
     private static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9;
 
     /**
-     * Request ConnectivityService display provisioning notification.
-     * arg1    = Whether to make the notification visible.
-     * arg2    = NetID.
-     * obj     = Intent to be launched when notification selected by user, null if !arg1.
-     */
-    public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 10;
-
-    /**
      * Message indicating sign-in app should be launched.
      * Sent by mLaunchCaptivePortalAppBroadcastReceiver when the
      * user touches the sign in notification, or sent by
      * ConnectivityService when the user touches the "sign into
      * network" button in the wifi access point detail page.
      */
-    public static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = BASE + 11;
+    private static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = BASE + 11;
 
     /**
      * Retest network to see if captive portal is still in place.
@@ -234,7 +211,6 @@
      * validation phase is completed.
      */
     private static final int CMD_PRIVATE_DNS_SETTINGS_CHANGED = BASE + 13;
-    public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = BASE + 14;
     private static final int CMD_EVALUATE_PRIVATE_DNS = BASE + 15;
 
     /**
@@ -263,23 +239,16 @@
     // Delay between reevaluations once a captive portal has been found.
     private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
 
-    private static final int NUM_VALIDATION_LOG_LINES = 20;
-
     private String mPrivateDnsProviderHostname = "";
 
-    public static boolean isValidationRequired(
-            NetworkCapabilities dfltNetCap, NetworkCapabilities nc) {
-        // TODO: Consider requiring validation for DUN networks.
-        return dfltNetCap.satisfiedByNetworkCapabilities(nc);
-    }
-
     private final Context mContext;
-    private final Handler mConnectivityServiceHandler;
-    private final NetworkAgentInfo mNetworkAgentInfo;
+    private final INetworkMonitorCallbacks mCallback;
     private final Network mNetwork;
+    private final Network mNonPrivateDnsBypassNetwork;
     private final int mNetId;
     private final TelephonyManager mTelephonyManager;
     private final WifiManager mWifiManager;
+    private final ConnectivityManager mCm;
     private final NetworkRequest mDefaultRequest;
     private final IpConnectivityLog mMetricsLog;
     private final Dependencies mDependencies;
@@ -292,6 +261,9 @@
     @Nullable
     private final CaptivePortalProbeSpec[] mCaptivePortalFallbackSpecs;
 
+    private NetworkCapabilities mNetworkCapabilities;
+    private LinkProperties mLinkProperties;
+
     @VisibleForTesting
     protected boolean mIsCaptivePortalCheckEnabled;
 
@@ -304,7 +276,7 @@
     // Avoids surfacing "Sign in to network" notification.
     private boolean mDontDisplaySigninNotification = false;
 
-    public boolean systemReady = false;
+    private volatile boolean mSystemReady = false;
 
     private final State mDefaultState = new DefaultState();
     private final State mValidatedState = new ValidatedState();
@@ -317,7 +289,7 @@
 
     private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null;
 
-    private final LocalLog validationLogs = new LocalLog(NUM_VALIDATION_LOG_LINES);
+    private final SharedLog mValidationLogs;
 
     private final Stopwatch mEvaluationTimer = new Stopwatch();
 
@@ -328,6 +300,7 @@
     private final Random mRandom;
     private int mNextFallbackUrlIndex = 0;
 
+
     private int mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
     private int mEvaluateAttempts = 0;
     private volatile int mProbeToken = 0;
@@ -338,17 +311,18 @@
     private final DnsStallDetector mDnsStallDetector;
     private long mLastProbeTime;
 
-    public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
-            NetworkRequest defaultRequest) {
-        this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog(),
+    public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
+            NetworkRequest defaultRequest, SharedLog validationLog) {
+        this(context, cb, network, defaultRequest, new IpConnectivityLog(), validationLog,
                 Dependencies.DEFAULT);
     }
 
     @VisibleForTesting
-    protected NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
-            NetworkRequest defaultRequest, IpConnectivityLog logger, Dependencies deps) {
+    protected NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
+            NetworkRequest defaultRequest, IpConnectivityLog logger, SharedLog validationLogs,
+            Dependencies deps) {
         // Add suffix indicating which NetworkMonitor we're talking about.
-        super(TAG + networkAgentInfo.name());
+        super(TAG + "/" + network.netId);
 
         // Logs with a tag of the form given just above, e.g.
         //     <timestamp>   862  2402 D NetworkMonitor/NetworkAgentInfo [WIFI () - 100]: ...
@@ -356,15 +330,18 @@
 
         mContext = context;
         mMetricsLog = logger;
-        mConnectivityServiceHandler = handler;
+        mValidationLogs = validationLogs;
+        mCallback = cb;
         mDependencies = deps;
-        mNetworkAgentInfo = networkAgentInfo;
-        mNetwork = deps.getNetwork(networkAgentInfo).getPrivateDnsBypassingCopy();
+        mNonPrivateDnsBypassNetwork = network;
+        mNetwork = deps.getPrivateDnsBypassNetwork(network);
         mNetId = mNetwork.netId;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
         mDefaultRequest = defaultRequest;
 
+        // CHECKSTYLE:OFF IndentationCheck
         addState(mDefaultState);
         addState(mMaybeNotifyState, mDefaultState);
             addState(mEvaluatingState, mMaybeNotifyState);
@@ -374,12 +351,13 @@
         addState(mEvaluatingPrivateDnsState, mDefaultState);
         addState(mValidatedState, mDefaultState);
         setInitialState(mDefaultState);
+        // CHECKSTYLE:ON IndentationCheck
 
         mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled();
         mUseHttps = getUseHttpsValidation();
         mCaptivePortalUserAgent = getCaptivePortalUserAgent();
         mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
-        mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl(deps, context));
+        mCaptivePortalHttpUrl = makeURL(deps.getCaptivePortalServerHttpUrl(context));
         mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
         mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
         mRandom = deps.getRandom();
@@ -390,7 +368,13 @@
         mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
         mDataStallEvaluationType = getDataStallEvalutionType();
 
-        start();
+        // mLinkProperties and mNetworkCapbilities must never be null or we will NPE.
+        // Provide empty objects in case we are started and the network disconnects before
+        // we can ever fetch them.
+        // TODO: Delete ASAP.
+        mLinkProperties = new LinkProperties();
+        mNetworkCapabilities = new NetworkCapabilities();
+        mNetworkCapabilities.clearAll();
     }
 
     /**
@@ -401,6 +385,14 @@
     }
 
     /**
+     * Send a notification to NetworkMonitor indicating that there was a DNS query response event.
+     * @param returnCode the DNS return code of the response.
+     */
+    public void notifyDnsResponse(int returnCode) {
+        sendMessage(EVENT_DNS_NOTIFICATION, returnCode);
+    }
+
+    /**
      * Send a notification to NetworkMonitor indicating that private DNS settings have changed.
      * @param newCfg The new private DNS configuration.
      */
@@ -411,9 +403,75 @@
         sendMessage(CMD_PRIVATE_DNS_SETTINGS_CHANGED, newCfg);
     }
 
+    /**
+     * Send a notification to NetworkMonitor indicating that the system is ready.
+     */
+    public void notifySystemReady() {
+        // No need to run on the handler thread: mSystemReady is volatile and read only once on the
+        // isCaptivePortal() thread.
+        mSystemReady = true;
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that the network is now connected.
+     */
+    public void notifyNetworkConnected() {
+        sendMessage(CMD_NETWORK_CONNECTED);
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that the network is now disconnected.
+     */
+    public void notifyNetworkDisconnected() {
+        sendMessage(CMD_NETWORK_DISCONNECTED);
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that link properties have changed.
+     */
+    public void notifyLinkPropertiesChanged() {
+        getHandler().post(() -> {
+            updateLinkProperties();
+        });
+    }
+
+    private void updateLinkProperties() {
+        final LinkProperties lp = mCm.getLinkProperties(mNetwork);
+        // If null, we should soon get a message that the network was disconnected, and will stop.
+        if (lp != null) {
+            // TODO: send LinkProperties parceled in notifyLinkPropertiesChanged() and start().
+            mLinkProperties = lp;
+        }
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that network capabilities have changed.
+     */
+    public void notifyNetworkCapabilitiesChanged() {
+        getHandler().post(() -> {
+            updateNetworkCapabilities();
+        });
+    }
+
+    private void updateNetworkCapabilities() {
+        final NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
+        // If null, we should soon get a message that the network was disconnected, and will stop.
+        if (nc != null) {
+            // TODO: send NetworkCapabilities parceled in notifyNetworkCapsChanged() and start().
+            mNetworkCapabilities = nc;
+        }
+    }
+
+    /**
+     * Request the captive portal application to be launched.
+     */
+    public void launchCaptivePortalApp() {
+        sendMessage(CMD_LAUNCH_CAPTIVE_PORTAL_APP);
+    }
+
     @Override
     protected void log(String s) {
-        if (DBG) Log.d(TAG + "/" + mNetworkAgentInfo.name(), s);
+        if (DBG) Log.d(TAG + "/" + mNetwork.netId, s);
     }
 
     private void validationLog(int probeType, Object url, String msg) {
@@ -423,11 +481,7 @@
 
     private void validationLog(String s) {
         if (DBG) log(s);
-        validationLogs.log(s);
-    }
-
-    public ReadOnlyLocalLog getValidationLogs() {
-        return validationLogs.readOnlyLocalLog();
+        mValidationLogs.log(s);
     }
 
     private ValidationStage validationStage() {
@@ -435,20 +489,46 @@
     }
 
     private boolean isValidationRequired() {
-        return isValidationRequired(
-                mDefaultRequest.networkCapabilities, mNetworkAgentInfo.networkCapabilities);
+        return NetworkMonitorUtils.isValidationRequired(
+                mDefaultRequest.networkCapabilities, mNetworkCapabilities);
     }
 
 
-    private void notifyNetworkTestResultInvalid(Object obj) {
-        mConnectivityServiceHandler.sendMessage(obtainMessage(
-                EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId, obj));
+    private void notifyNetworkTested(int result, @Nullable String redirectUrl) {
+        try {
+            mCallback.notifyNetworkTested(result, redirectUrl);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending network test result", e);
+        }
+    }
+
+    private void showProvisioningNotification(String action) {
+        try {
+            mCallback.showProvisioningNotification(action);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error showing provisioning notification", e);
+        }
+    }
+
+    private void hideProvisioningNotification() {
+        try {
+            mCallback.hideProvisioningNotification();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error hiding provisioning notification", e);
+        }
     }
 
     // DefaultState is the parent of all States.  It exists only to handle CMD_* messages but
     // does not entail any real state (hence no enter() or exit() routines).
     private class DefaultState extends State {
         @Override
+        public void enter() {
+            // TODO: have those passed parceled in start() and remove this
+            updateLinkProperties();
+            updateNetworkCapabilities();
+        }
+
+        @Override
         public boolean processMessage(Message message) {
             switch (message.what) {
                 case CMD_NETWORK_CONNECTED:
@@ -499,7 +579,7 @@
                         case APP_RETURN_UNWANTED:
                             mDontDisplaySigninNotification = true;
                             mUserDoesNotWant = true;
-                            notifyNetworkTestResultInvalid(null);
+                            notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
                             // TODO: Should teardown network.
                             mUidResponsibleForReeval = 0;
                             transitionTo(mEvaluatingState);
@@ -563,8 +643,7 @@
         public void enter() {
             maybeLogEvaluationResult(
                     networkEventType(validationStage(), EvaluationResult.VALIDATED));
-            mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
-                    NETWORK_TEST_RESULT_VALID, mNetId, null));
+            notifyNetworkTested(INetworkMonitor.NETWORK_TEST_RESULT_VALID, null);
             mValidations++;
         }
 
@@ -633,8 +712,7 @@
 
         @Override
         public void exit() {
-            Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0, mNetId, null);
-            mConnectivityServiceHandler.sendMessage(message);
+            hideProvisioningNotification();
         }
     }
 
@@ -751,9 +829,7 @@
                         CMD_LAUNCH_CAPTIVE_PORTAL_APP);
             }
             // Display the sign in notification.
-            Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1, mNetId,
-                    mLaunchCaptivePortalAppBroadcastReceiver.getPendingIntent());
-            mConnectivityServiceHandler.sendMessage(message);
+            showProvisioningNotification(mLaunchCaptivePortalAppBroadcastReceiver.mAction);
             // Retest for captive portal occasionally.
             sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
                     CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
@@ -839,12 +915,15 @@
         }
 
         private void notifyPrivateDnsConfigResolved() {
-            mConnectivityServiceHandler.sendMessage(obtainMessage(
-                    EVENT_PRIVATE_DNS_CONFIG_RESOLVED, 0, mNetId, mPrivateDnsConfig));
+            try {
+                mCallback.notifyPrivateDnsConfigResolved(mPrivateDnsConfig.toParcel());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sending private DNS config resolved notification", e);
+            }
         }
 
         private void handlePrivateDnsEvaluationFailure() {
-            notifyNetworkTestResultInvalid(null);
+            notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
 
             // Queue up a re-evaluation with backoff.
             //
@@ -865,7 +944,7 @@
                     + oneTimeHostnameSuffix;
             final Stopwatch watch = new Stopwatch().start();
             try {
-                final InetAddress[] ips = mNetworkAgentInfo.network().getAllByName(host);
+                final InetAddress[] ips = mNonPrivateDnsBypassNetwork.getAllByName(host);
                 final long time = watch.stop();
                 final String strIps = Arrays.toString(ips);
                 final boolean success = (ips != null && ips.length > 0);
@@ -915,12 +994,12 @@
                         // state (even if no Private DNS validation required).
                         transitionTo(mEvaluatingPrivateDnsState);
                     } else if (probeResult.isPortal()) {
-                        notifyNetworkTestResultInvalid(probeResult.redirectUrl);
+                        notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
                         mLastPortalProbeResult = probeResult;
                         transitionTo(mCaptivePortalState);
                     } else {
                         logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
-                        notifyNetworkTestResultInvalid(probeResult.redirectUrl);
+                        notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
                         transitionTo(mWaitingForNextProbeState);
                     }
                     return HANDLED;
@@ -996,18 +1075,18 @@
         }
     }
 
-    public boolean getIsCaptivePortalCheckEnabled() {
+    private boolean getIsCaptivePortalCheckEnabled() {
         String symbol = Settings.Global.CAPTIVE_PORTAL_MODE;
         int defaultValue = Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT;
         int mode = mDependencies.getSetting(mContext, symbol, defaultValue);
         return mode != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
     }
 
-    public boolean getUseHttpsValidation() {
+    private boolean getUseHttpsValidation() {
         return mDependencies.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
     }
 
-    public boolean getWifiScansAlwaysAvailableDisabled() {
+    private boolean getWifiScansAlwaysAvailableDisabled() {
         return mDependencies.getSetting(
                 mContext, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0;
     }
@@ -1040,15 +1119,6 @@
                 DEFAULT_DATA_STALL_EVALUATION_TYPES);
     }
 
-    // Static for direct access by ConnectivityService
-    public static String getCaptivePortalServerHttpUrl(Context context) {
-        return getCaptivePortalServerHttpUrl(Dependencies.DEFAULT, context);
-    }
-
-    public static String getCaptivePortalServerHttpUrl(Dependencies deps, Context context) {
-        return deps.getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
-    }
-
     private URL[] makeCaptivePortalFallbackUrls() {
         try {
             String separator = ",";
@@ -1144,7 +1214,7 @@
         // 3. PAC scripts are sometimes used to block or restrict Internet access and may in
         //    fact block fetching of the generate_204 URL which would lead to false negative
         //    results for network validation.
-        final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
+        final ProxyInfo proxyInfo = mLinkProperties.getHttpProxy();
         if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
             pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
             if (pacUrl == null) {
@@ -1416,89 +1486,86 @@
             return;
         }
 
-        if (!systemReady) {
+        if (!mSystemReady) {
             return;
         }
 
         Intent latencyBroadcast =
-                new Intent(ConnectivityConstants.ACTION_NETWORK_CONDITIONS_MEASURED);
-        switch (mNetworkAgentInfo.networkInfo.getType()) {
-            case ConnectivityManager.TYPE_WIFI:
-                WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
-                if (currentWifiInfo != null) {
-                    // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
-                    // surrounded by double quotation marks (thus violating the Javadoc), but this
-                    // was changed to match the Javadoc in API 17. Since clients may have started
-                    // sanitizing the output of this method since API 17 was released, we should
-                    // not change it here as it would become impossible to tell whether the SSID is
-                    // simply being surrounded by quotes due to the API, or whether those quotes
-                    // are actually part of the SSID.
-                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_SSID,
-                            currentWifiInfo.getSSID());
-                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_BSSID,
-                            currentWifiInfo.getBSSID());
-                } else {
-                    if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
-                    return;
-                }
-                break;
-            case ConnectivityManager.TYPE_MOBILE:
-                latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_NETWORK_TYPE,
-                        mTelephonyManager.getNetworkType());
-                List<CellInfo> info = mTelephonyManager.getAllCellInfo();
-                if (info == null) return;
-                int numRegisteredCellInfo = 0;
-                for (CellInfo cellInfo : info) {
-                    if (cellInfo.isRegistered()) {
-                        numRegisteredCellInfo++;
-                        if (numRegisteredCellInfo > 1) {
-                            if (VDBG) {
-                                logw("more than one registered CellInfo."
-                                        + " Can't tell which is active.  Bailing.");
-                            }
-                            return;
+                new Intent(NetworkMonitorUtils.ACTION_NETWORK_CONDITIONS_MEASURED);
+        if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI)) {
+            WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
+            if (currentWifiInfo != null) {
+                // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
+                // surrounded by double quotation marks (thus violating the Javadoc), but this
+                // was changed to match the Javadoc in API 17. Since clients may have started
+                // sanitizing the output of this method since API 17 was released, we should
+                // not change it here as it would become impossible to tell whether the SSID is
+                // simply being surrounded by quotes due to the API, or whether those quotes
+                // are actually part of the SSID.
+                latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_SSID,
+                        currentWifiInfo.getSSID());
+                latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_BSSID,
+                        currentWifiInfo.getBSSID());
+            } else {
+                if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
+                return;
+            }
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_WIFI);
+        } else if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_NETWORK_TYPE,
+                    mTelephonyManager.getNetworkType());
+            List<CellInfo> info = mTelephonyManager.getAllCellInfo();
+            if (info == null) return;
+            int numRegisteredCellInfo = 0;
+            for (CellInfo cellInfo : info) {
+                if (cellInfo.isRegistered()) {
+                    numRegisteredCellInfo++;
+                    if (numRegisteredCellInfo > 1) {
+                        if (VDBG) {
+                            logw("more than one registered CellInfo."
+                                    + " Can't tell which is active.  Bailing.");
                         }
-                        if (cellInfo instanceof CellInfoCdma) {
-                            CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoGsm) {
-                            CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoLte) {
-                            CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoWcdma) {
-                            CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else {
-                            if (VDBG) logw("Registered cellinfo is unrecognized");
-                            return;
-                        }
+                        return;
+                    }
+                    if (cellInfo instanceof CellInfoCdma) {
+                        CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else if (cellInfo instanceof CellInfoGsm) {
+                        CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else if (cellInfo instanceof CellInfoLte) {
+                        CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else if (cellInfo instanceof CellInfoWcdma) {
+                        CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else {
+                        if (VDBG) logw("Registered cellinfo is unrecognized");
+                        return;
                     }
                 }
-                break;
-            default:
-                return;
+            }
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
+        } else {
+            return;
         }
-        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CONNECTIVITY_TYPE,
-                mNetworkAgentInfo.networkInfo.getType());
-        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_RECEIVED,
+        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_RESPONSE_RECEIVED,
                 responseReceived);
-        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_REQUEST_TIMESTAMP_MS,
+        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_REQUEST_TIMESTAMP_MS,
                 requestTimestampMs);
 
         if (responseReceived) {
-            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_IS_CAPTIVE_PORTAL,
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_IS_CAPTIVE_PORTAL,
                     isCaptivePortal);
-            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_TIMESTAMP_MS,
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_RESPONSE_TIMESTAMP_MS,
                     responseTimestampMs);
         }
         mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
-                ConnectivityConstants.PERMISSION_ACCESS_NETWORK_CONDITIONS);
+                NetworkMonitorUtils.PERMISSION_ACCESS_NETWORK_CONDITIONS);
     }
 
     private void logNetworkEvent(int evtype) {
-        int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
+        int[] transports = mNetworkCapabilities.getTransportTypes();
         mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype));
     }
 
@@ -1520,14 +1587,14 @@
 
     private void maybeLogEvaluationResult(int evtype) {
         if (mEvaluationTimer.isRunning()) {
-            int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
+            int[] transports = mNetworkCapabilities.getTransportTypes();
             mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype, mEvaluationTimer.stop()));
             mEvaluationTimer.reset();
         }
     }
 
     private void logValidationProbe(long durationMs, int probeType, int probeResult) {
-        int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
+        int[] transports = mNetworkCapabilities.getTransportTypes();
         boolean isFirstValidation = validationStage().mIsFirstValidation;
         ValidationProbeEvent ev = new ValidationProbeEvent();
         ev.probeType = ValidationProbeEvent.makeProbeType(probeType, isFirstValidation);
@@ -1537,9 +1604,9 @@
     }
 
     @VisibleForTesting
-    public static class Dependencies {
-        public Network getNetwork(NetworkAgentInfo networkAgentInfo) {
-            return new OneAddressPerFamilyNetwork(networkAgentInfo.network());
+    static class Dependencies {
+        public Network getPrivateDnsBypassNetwork(Network network) {
+            return new OneAddressPerFamilyNetwork(network);
         }
 
         public Random getRandom() {
@@ -1547,6 +1614,13 @@
         }
 
         /**
+         * Get the captive portal server HTTP URL that is configured on the device.
+         */
+        public String getCaptivePortalServerHttpUrl(Context context) {
+            return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(context);
+        }
+
+        /**
          * Get the value of a global integer setting.
          * @param symbol Name of the setting
          * @param defaultValue Value to return if the setting is not defined.
@@ -1666,7 +1740,7 @@
         boolean result = false;
         // Reevaluation will generate traffic. Thus, set a minimal reevaluation timer to limit the
         // possible traffic cost in metered network.
-        if (mNetworkAgentInfo.networkCapabilities.isMetered()
+        if (mNetworkCapabilities.isMetered()
                 && (SystemClock.elapsedRealtime() - getLastProbeTime()
                 < mDataStallMinEvaluateTime)) {
             return false;
diff --git a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
similarity index 68%
rename from tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index 6e07b26..d31fa77 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -16,6 +16,14 @@
 
 package com.android.server.connectivity;
 
+import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 
 import static org.junit.Assert.assertTrue;
@@ -24,13 +32,21 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.Intent;
+import android.net.CaptivePortal;
 import android.net.ConnectivityManager;
+import android.net.INetworkMonitorCallbacks;
+import android.net.InetAddresses;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -38,9 +54,12 @@
 import android.net.NetworkRequest;
 import android.net.captiveportal.CaptivePortalProbeResult;
 import android.net.metrics.IpConnectivityLog;
+import android.net.util.SharedLog;
 import android.net.wifi.WifiManager;
+import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -50,8 +69,10 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
@@ -68,21 +89,23 @@
     private static final String LOCATION_HEADER = "location";
 
     private @Mock Context mContext;
-    private @Mock Handler mHandler;
     private @Mock IpConnectivityLog mLogger;
-    private @Mock NetworkAgentInfo mAgent;
-    private @Mock NetworkAgentInfo mNotMeteredAgent;
+    private @Mock SharedLog mValidationLogger;
     private @Mock NetworkInfo mNetworkInfo;
-    private @Mock NetworkRequest mRequest;
+    private @Mock ConnectivityManager mCm;
     private @Mock TelephonyManager mTelephony;
     private @Mock WifiManager mWifi;
-    private @Mock Network mNetwork;
     private @Mock HttpURLConnection mHttpConnection;
     private @Mock HttpURLConnection mHttpsConnection;
     private @Mock HttpURLConnection mFallbackConnection;
     private @Mock HttpURLConnection mOtherFallbackConnection;
     private @Mock Random mRandom;
     private @Mock NetworkMonitor.Dependencies mDependencies;
+    private @Mock INetworkMonitorCallbacks mCallbacks;
+    private @Spy Network mNetwork = new Network(TEST_NETID);
+    private NetworkRequest mRequest;
+
+    private static final int TEST_NETID = 4242;
 
     private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
     private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
@@ -93,33 +116,37 @@
     private static final int RETURN_CODE_DNS_SUCCESS = 0;
     private static final int RETURN_CODE_DNS_TIMEOUT = 255;
 
+    private static final int HANDLER_TIMEOUT_MS = 1000;
+
+    private static final LinkProperties TEST_LINKPROPERTIES = new LinkProperties();
+
+    private static final NetworkCapabilities METERED_CAPABILITIES = new NetworkCapabilities()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .addCapability(NET_CAPABILITY_INTERNET);
+
+    private static final NetworkCapabilities NOT_METERED_CAPABILITIES = new NetworkCapabilities()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .addCapability(NET_CAPABILITY_INTERNET)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+
+    private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+
     @Before
     public void setUp() throws IOException {
         MockitoAnnotations.initMocks(this);
-        mAgent.linkProperties = new LinkProperties();
-        mAgent.networkCapabilities = new NetworkCapabilities()
-                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        mAgent.networkInfo = mNetworkInfo;
-
-        mNotMeteredAgent.linkProperties = new LinkProperties();
-        mNotMeteredAgent.networkCapabilities = new NetworkCapabilities()
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-        mNotMeteredAgent.networkInfo = mNetworkInfo;
-
-        when(mAgent.network()).thenReturn(mNetwork);
-        when(mDependencies.getNetwork(any())).thenReturn(mNetwork);
+        when(mDependencies.getPrivateDnsBypassNetwork(any())).thenReturn(mNetwork);
         when(mDependencies.getRandom()).thenReturn(mRandom);
         when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
                 .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
         when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
                 anyInt())).thenReturn(1);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL),
-                anyString())).thenReturn(TEST_HTTP_URL);
+        when(mDependencies.getCaptivePortalServerHttpUrl(any())).thenReturn(TEST_HTTP_URL);
         when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL),
                 anyString())).thenReturn(TEST_HTTPS_URL);
-        when(mNetwork.getPrivateDnsBypassingCopy()).thenReturn(mNetwork);
+        doReturn(mNetwork).when(mNetwork).getPrivateDnsBypassingCopy();
 
+        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
         when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
         when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
 
@@ -129,7 +156,7 @@
         setFallbackSpecs(null); // Test with no fallback spec by default
         when(mRandom.nextInt()).thenReturn(0);
 
-        when(mNetwork.openConnection(any())).then((invocation) -> {
+        doAnswer((invocation) -> {
             URL url = invocation.getArgument(0);
             switch(url.toString()) {
                 case TEST_HTTP_URL:
@@ -144,12 +171,20 @@
                     fail("URL not mocked: " + url.toString());
                     return null;
             }
-        });
+        }).when(mNetwork).openConnection(any());
         when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
         when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
-        when(mNetwork.getAllByName(any())).thenReturn(new InetAddress[] {
-            InetAddress.parseNumericAddress("192.168.0.0")
-        });
+        doReturn(new InetAddress[] {
+                InetAddresses.parseNumericAddress("192.168.0.0")
+        }).when(mNetwork).getAllByName(any());
+
+        mRequest = new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                .build();
+        // Default values. Individual tests can override these.
+        when(mCm.getLinkProperties(any())).thenReturn(TEST_LINKPROPERTIES);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
 
         setMinDataStallEvaluateInterval(500);
         setDataStallEvaluationType(1 << DATA_STALL_EVALUATION_TYPE_DNS);
@@ -160,10 +195,10 @@
     private class WrappedNetworkMonitor extends NetworkMonitor {
         private long mProbeTime = 0;
 
-        WrappedNetworkMonitor(Context context, Handler handler,
-                NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
+        WrappedNetworkMonitor(Context context, Network network, NetworkRequest defaultRequest,
                 IpConnectivityLog logger, Dependencies deps) {
-                super(context, handler, networkAgentInfo, defaultRequest, logger, deps);
+                super(context, mCallbacks, network, defaultRequest, logger,
+                        new SharedLog("test_nm"), deps);
         }
 
         @Override
@@ -176,19 +211,39 @@
         }
     }
 
-    WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
-        return new WrappedNetworkMonitor(
-                mContext, mHandler, mAgent, mRequest, mLogger, mDependencies);
+    private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
+        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
+                mContext, mNetwork, mRequest, mLogger, mDependencies);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+        nm.start();
+        waitForIdle(nm.getHandler());
+        return nm;
     }
 
-    WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
-        return new WrappedNetworkMonitor(
-                mContext, mHandler, mNotMeteredAgent, mRequest, mLogger, mDependencies);
+    private WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
+        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
+                mContext, mNetwork, mRequest, mLogger, mDependencies);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(NOT_METERED_CAPABILITIES);
+        nm.start();
+        waitForIdle(nm.getHandler());
+        return nm;
     }
 
-    NetworkMonitor makeMonitor() {
-        return new NetworkMonitor(
-                mContext, mHandler, mAgent, mRequest, mLogger, mDependencies);
+    private NetworkMonitor makeMonitor() {
+        final NetworkMonitor nm = new NetworkMonitor(
+                mContext, mCallbacks, mNetwork, mRequest, mLogger, mValidationLogger,
+                mDependencies);
+        nm.start();
+        waitForIdle(nm.getHandler());
+        return nm;
+    }
+
+    private void waitForIdle(Handler handler) {
+        final ConditionVariable cv = new ConditionVariable(false);
+        handler.post(cv::open);
+        if (!cv.block(HANDLER_TIMEOUT_MS)) {
+            fail("Timed out waiting for handler");
+        }
     }
 
     @Test
@@ -319,6 +374,15 @@
     }
 
     @Test
+    public void testIsCaptivePortal_IgnorePortals() throws IOException {
+        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
+        setSslException(mHttpsConnection);
+        setPortal302(mHttpConnection);
+
+        assertNotPortal(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
     public void testIsDataStall_EvaluationDisabled() {
         setDataStallEvaluationType(0);
         WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
@@ -390,6 +454,63 @@
         assertFalse(wrappedMonitor.isDataStall());
     }
 
+    @Test
+    public void testBrokenNetworkNotValidated() throws Exception {
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 404);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+
+        final NetworkMonitor nm = makeMonitor();
+        nm.notifyNetworkConnected();
+
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
+    }
+
+    @Test
+    public void testNoInternetCapabilityValidated() throws Exception {
+        when(mCm.getNetworkCapabilities(any())).thenReturn(NO_INTERNET_CAPABILITIES);
+
+        final NetworkMonitor nm = makeMonitor();
+        nm.notifyNetworkConnected();
+
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+        verify(mNetwork, never()).openConnection(any());
+    }
+
+    @Test
+    public void testLaunchCaptivePortalApp() throws Exception {
+        setSslException(mHttpsConnection);
+        setPortal302(mHttpConnection);
+
+        final NetworkMonitor nm = makeMonitor();
+        nm.notifyNetworkConnected();
+
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .showProvisioningNotification(any());
+
+        // Check that startCaptivePortalApp sends the expected intent.
+        nm.launchCaptivePortalApp();
+
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .startActivityAsUser(intentCaptor.capture(), eq(UserHandle.CURRENT));
+        final Intent intent = intentCaptor.getValue();
+        assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction());
+        final Network network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
+        assertEquals(TEST_NETID, network.netId);
+
+        // Have the app report that the captive portal is dismissed, and check that we revalidate.
+        setStatus(mHttpsConnection, 204);
+        setStatus(mHttpConnection, 204);
+        final CaptivePortal captivePortal = intent.getParcelableExtra(EXTRA_CAPTIVE_PORTAL);
+        captivePortal.reportCaptivePortalDismissed();
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+    }
+
     private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
         for (int i = 0; i < count; i++) {
             wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
@@ -440,6 +561,11 @@
                 eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
     }
 
+    private void setCaptivePortalMode(int mode) {
+        when(mDependencies.getSetting(any(),
+                eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())).thenReturn(mode);
+    }
+
     private void assertPortal(CaptivePortalProbeResult result) {
         assertTrue(result.isPortal());
         assertFalse(result.isFailed());
@@ -459,12 +585,12 @@
     }
 
     private void setSslException(HttpURLConnection connection) throws IOException {
-        when(connection.getResponseCode()).thenThrow(new SSLHandshakeException("Invalid cert"));
+        doThrow(new SSLHandshakeException("Invalid cert")).when(connection).getResponseCode();
     }
 
     private void set302(HttpURLConnection connection, String location) throws IOException {
         setStatus(connection, 302);
-        when(connection.getHeaderField(LOCATION_HEADER)).thenReturn(location);
+        doReturn(location).when(connection).getHeaderField(LOCATION_HEADER);
     }
 
     private void setPortal302(HttpURLConnection connection) throws IOException {
@@ -472,7 +598,7 @@
     }
 
     private void setStatus(HttpURLConnection connection, int status) throws IOException {
-        when(connection.getResponseCode()).thenReturn(status);
+        doReturn(status).when(connection).getResponseCode();
     }
 }
 
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index 933ff3f..9b57186 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -90,7 +90,7 @@
     <string name="anonymous_source_continue" msgid="4375745439457209366">"Fortsæt"</string>
     <string name="external_sources_settings" msgid="4046964413071713807">"Indstillinger"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"Installerer/afinstallerer Wear-apps"</string>
-    <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Underretning om appinstallation"</string>
+    <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Notifikation om appinstallation"</string>
     <string name="notification_installation_success_message" msgid="6450467996056038442">"Appen er installeret"</string>
     <string name="notification_installation_success_status" msgid="3172502643504323321">"\"<xliff:g id="APPNAME">%1$s</xliff:g>\" er installeret"</string>
 </resources>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 2182631..4deab35 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -59,7 +59,7 @@
     <string name="uninstall_update_text" msgid="863648314632448705">"फॅक्टरी आवृत्तीसह हे अ‍ॅप बदलायचे का? सर्व डेटा काढला जाईल."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"फॅक्टरी आवृत्तीसह हे अ‍ॅप बदलायचे? सर्व डेटा काढला जाईल. हे कार्य प्रोफाइल असलेल्यांसह या डिव्हाइसच्या सर्व वापरकर्त्यांना प्रभावित करते."</string>
     <string name="uninstall_remove_contributed_files" msgid="2048594420923203453">"<xliff:g id="SIZE">%1$s</xliff:g> आकाराच्या संबंधित मीडिया फायलीदेखील काढा."</string>
-    <string name="uninstall_keep_data" msgid="7002379587465487550">"अॅप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
+    <string name="uninstall_keep_data" msgid="7002379587465487550">"ॲप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
     <string name="uninstalling_notification_channel" msgid="840153394325714653">"अनइंस्टॉल रन होत आहेत"</string>
     <string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"अनइंस्टॉल करता आले नाही"</string>
     <string name="uninstalling" msgid="8709566347688966845">"अनइंस्टॉल करत आहे…"</string>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 1dd7838..ac34a99e 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuwe rugsteunwagwoord ingestel"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nuwe wagwoord en bevestiging stem nie ooreen nie"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Rugsteunwagwoord kon nie ingestel word nie"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laai tans …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Lewendig (verstek)"</item>
     <item msgid="8446070607501413455">"Natuurlik"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vra elke keer"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat jy dit afskakel"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sopas"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aansluitingprogram om opgedateerde grafikadrywer in ontwikkeling te gebruik"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Foonluidspreker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 2ce5f44..9405b7d 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"አዲስ የምትኬ ይለፍ ቃል ተዋቅሯል"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"አዲሱ የይለፍ ቃል እና ማረጋገጫው አይዛመዱም"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"የምትኬ ይለፍ ቃል ማዋቀር አልተሳካም"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"በመጫን ላይ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ነዛሪ (ነባሪ)"</item>
     <item msgid="8446070607501413455">"ተፈጥሯዊ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ሁልጊዜ ጠይቅ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"እስኪያጠፉት ድረስ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ልክ አሁን"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"በግንባታ ላይ የተዘመነ የግራፊክስ ነጂን ለመጠቀም መተግበሪያን መርጠው ያስገቡ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"የስልክ ድምጽ ማጉያ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 23f3a12..8ffd7a9 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"تم تعيين كلمة مرور احتياطية جديدة"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"كلمة المرور الجديدة وتأكيدها لا يتطابقان"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"تعذّر تعيين كلمة مرور احتياطية"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"جارٍ التحميل…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"نابض بالحياة (تلقائي)"</item>
     <item msgid="8446070607501413455">"طبيعي"</item>
@@ -453,6 +454,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"الطلب في كل مرة"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"إلى أن توقف الوضع يدويًا"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"للتو"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"فعِّل التطبيق لاستخدام برنامج تشغيل الرسومات المُحدَّث في تطوير البرامج."</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"مكبر صوت الهاتف"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
index 39c0b00..c0a2179 100644
--- a/packages/SettingsLib/res/values-as/arrays.xml
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -40,7 +40,7 @@
     <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰি থকা হৈছে…"</item>
     <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ জৰিয়তে সত্যাপন কৰি থকা হৈছে…"</item>
     <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ আইপি ঠিকনা পৰা সংগ্ৰহ কৰি থকা হৈছে…"</item>
-    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰা হ\'ল"</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰা হ’ল"</item>
     <item msgid="1330262655415760617">"স্থগিত"</item>
     <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ পৰা সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</item>
     <item msgid="197508606402264311">"সংযোগ বিচ্ছিন্ন"</item>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 86d1459..3ad13bd 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -32,11 +32,11 @@
     <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\'ৰ সৈতে সংযোগ কৰিব পৰা নাই"</string>
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"পাছৱৰ্ড পৰীক্ষা কৰি আকৌ চেষ্টা কৰক"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"পৰিসৰৰ ভিতৰত নাই"</string>
-    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্ৰিয়ভাৱে সংযোগ নহ\'ব"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্ৰিয়ভাৱে সংযোগ নহ’ব"</string>
     <string name="wifi_no_internet" msgid="4663834955626848401">"ইণ্টাৰনেট সংযোগ নাই"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>এ ছেভ কৰিছে"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s মাধ্যমেদি স্বয়ংক্ৰিয়ভাৱে সংযোগ কৰা হৈছে"</string>
-    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ\'ল"</string>
+    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ’ল"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ৰ মাধ্যমেদি সংযোগ কৰা হৈছে"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"সংযোজিত, ইণ্টাৰনেট নাই"</string>
@@ -55,16 +55,16 @@
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</string>
     <string name="bluetooth_connecting" msgid="8555009514614320497">"সংযোগ কৰি থকা হৈছে…"</string>
-    <string name="bluetooth_connected" msgid="5427152882755735944">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> সংযোগ কৰা হ\'ল"</string>
+    <string name="bluetooth_connected" msgid="5427152882755735944">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> সংযোগ কৰা হ’ল"</string>
     <string name="bluetooth_pairing" msgid="1426882272690346242">"যোৰা লগোৱা হৈছে…"</string>
-    <string name="bluetooth_connected_no_headset" msgid="616068069034994802">"সংযোগ কৰা হ\'ল (ফ\'ন নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"সংযোগ কৰা হ\'ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"সংযোগ কৰা হ\'ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"সংযোগ কৰা হ\'ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"সংযোগ কৰা হ\'ল, বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"সংযোগ কৰা হ\'ল (ফ\'ন নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"সংযোগ কৰা হ\'ল (মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"সংযোগ কৰা হ\'ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset" msgid="616068069034994802">"সংযোগ কৰা হ’ল (ফ\'ন নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"সংযোগ কৰা হ’ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"সংযোগ কৰা হ’ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"সংযোগ কৰা হ’ল, বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"সংযোগ কৰা হ’ল (ফ\'ন নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"সংযোগ কৰা হ’ল (মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
     <string name="bluetooth_active_battery_level" msgid="3149689299296462009">"সক্ৰিয়, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি"</string>
     <string name="bluetooth_battery_level" msgid="1447164613319663655">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি"</string>
     <string name="bluetooth_active_no_battery_level" msgid="8380223546730241956">"সক্ৰিয়"</string>
@@ -81,9 +81,9 @@
     <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"এইচ্ছডি অডি\'অ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
     <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"এইচ্ছডি অডিঅ’"</string>
     <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"শ্ৰৱণ যন্ত্ৰ"</string>
-    <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্ৰৱণ যন্ত্ৰৰ লগত সংযোগ কৰা হ\'ল"</string>
+    <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্ৰৱণ যন্ত্ৰৰ লগত সংযোগ কৰা হ’ল"</string>
     <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিঅ’লৈ সংযোগ হৈছে"</string>
-    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিঅ\'ৰ লগত সংযোগ কৰা হ\'ল"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফ’ন অডিঅ\'ৰ লগত সংযোগ কৰা হ’ল"</string>
     <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল ট্ৰান্সফাৰ ছাৰ্ভাৰৰ সৈতে সংযোজিত হৈ আছে"</string>
     <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"মেপৰ সৈতে সংযোগ কৰক"</string>
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAPৰ সৈতে সংযোজিত হৈ আছে"</string>
@@ -206,10 +206,10 @@
     <string name="mock_location_app_not_set" msgid="809543285495344223">"কোনো নকল অৱস্থান এপ্ নিৰ্ধাৰণ কৰা হোৱা নাই"</string>
     <string name="mock_location_app_set" msgid="8966420655295102685">"নকল অৱস্থানৰ এপ্: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="7044075693643009662">"নেটৱৰ্কিং"</string>
-    <string name="wifi_display_certification" msgid="8611569543791307533">"বেতাঁৰ ডিছপ্লে প্ৰমাণীকৰণ"</string>
+    <string name="wifi_display_certification" msgid="8611569543791307533">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণীকৰণ"</string>
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"ৱাই-ফাই ভাৰ্ব\'ছ লগিং সক্ষম কৰক"</string>
     <string name="wifi_connected_mac_randomization" msgid="3168165236877957767">"সংযুক্ত MAC যাদৃচ্ছিকৰণ"</string>
-    <string name="mobile_data_always_on" msgid="8774857027458200434">"ম\'বাইল ডেটা সদা-সক্ৰিয়"</string>
+    <string name="mobile_data_always_on" msgid="8774857027458200434">"ম’বাইল ডেটা সদা-সক্ৰিয়"</string>
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"পূৰ্ণ মাত্ৰাৰ ভলিউম অক্ষম কৰক"</string>
@@ -233,7 +233,7 @@
     <string name="private_dns_mode_provider" msgid="8354935160639360804">"ব্যক্তিগত ডিএনএছ প্ৰদানকাৰীৰ হোষ্টনাম"</string>
     <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ডিএনএছ সেৱা যোগানকাৰীৰ হ\'ষ্টনাম দিয়ক"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"সংযোগ কৰিব পৰা নগ\'ল"</string>
-    <string name="wifi_display_certification_summary" msgid="1155182309166746973">"বেতাঁৰ ডিছপ্লে প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
+    <string name="wifi_display_certification_summary" msgid="1155182309166746973">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string>
     <string name="wifi_connected_mac_randomization_summary" msgid="1743059848752201485">"ৱাই-ফাই নেটৱৰ্কৰ লগত সংযোগ কৰি থকাৰ সময়ত MAC ঠিকনা যাদৃচ্ছিক কৰক"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"নিৰিখ-নিৰ্দিষ্ট"</string>
@@ -249,7 +249,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"নকল অৱস্থানৰ অনুমতি দিয়ক"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"নকল অৱস্থানৰ অনুমতি দিয়ক"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"দৃশ্যৰ গুণাগুণ নিৰীক্ষণ সক্ষম কৰক"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ৱাই-ফাই থকা সময়তো সদায় ম\'বাইল ডেটা সক্ৰিয় ৰাখক (খৰতকীয়াকৈ নেটৱৰ্ক সলনি কৰিবৰ বাবে)।"</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ৱাই-ফাই থকা সময়তো সদায় ম’বাইল ডেটা সক্ৰিয় ৰাখক (খৰতকীয়াকৈ নেটৱৰ্ক সলনি কৰিবৰ বাবে)।"</string>
     <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"যদিহে উপলব্ধ হয় তেন্তে টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ ব্যৱহাৰ কৰক"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"ইউএছবি ডিবাগিঙৰ অনুমতি দিয়েনে?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"ইউএছবি ডিবাগ কৰা কাৰ্য কেৱল বিকাশৰ উদ্দেশ্যৰেহে কৰা হৈছে৷ আপোনাৰ কম্পিউটাৰ আৰু আপোনাৰ ডিভাইচৰ মাজত ডেটা প্ৰতিলিপি কৰিবলৈ এইটো ব্যৱহাৰ কৰক, কোনো জাননী নিদিয়াকৈয়ে আপোনাৰ ডিভাইচত এপ্‌সমূহ ইনষ্টল কৰক আৰু লগ ডেটা পঢ়ক৷"</string>
@@ -285,7 +285,7 @@
     <string name="show_touches_summary" msgid="6101183132903926324">"টিপিলে দৃশ্যায়িত ফীডবেক দিয়ক"</string>
     <string name="show_screen_updates" msgid="5470814345876056420">"পৃষ্ঠভাগৰ আপডেইট দেখুৱাওক"</string>
     <string name="show_screen_updates_summary" msgid="2569622766672785529">"আপডেইট হওতে গোটেই ৱিণ্ড পৃষ্ঠসমূহ ফ্লাশ্ব কৰক"</string>
-    <string name="show_hw_screen_updates" msgid="4117270979975470789">"আপডেট চাওক দেখুৱাওক"</string>
+    <string name="show_hw_screen_updates" msgid="4117270979975470789">"আপডে’ট চাওক দেখুৱাওক"</string>
     <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"অঁকাৰ সময়ত ৱিণ্ড\'ৰ ভিতৰত ফ্লাশ্ব দৰ্শন"</string>
     <string name="show_hw_layers_updates" msgid="5645728765605699821">"হাৰ্ডৱেৰৰ তৰপৰ আপডেইট দেখুৱাওক"</string>
     <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"হাৰ্ডৱেৰ লেয়াৰ আপডেইট হওতে সিঁহতক সেউজীয়া ৰঙেৰে ফ্লাশ্ব কৰক"</string>
@@ -327,9 +327,10 @@
     <string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ বেকআপ পাছৱৰ্ড"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপৰ পূৰ্ণ বেকআপ এতিয়ালৈকে সংৰক্ষিত অৱস্থাত নাই"</string>
     <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ডেস্কটপ সম্পূৰ্ণ বেকআপৰ বাবে পাছৱৰ্ডটো সলনি কৰিবলৈ বা আঁতৰাবলৈ টিপক"</string>
-    <string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন বেকআপ পাছৱৰ্ড ছেট কৰা হ\'ল"</string>
+    <string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন বেকআপ পাছৱৰ্ড ছেট কৰা হ’ল"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"নতুন পাছৱৰ্ডটোৰ লগত নিশ্চিত কৰা পাছৱৰ্ডটো মিলা নাই"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"বেকআপ পাছৱৰ্ড নিৰ্ধাৰণ কৰিব পৰা নহ\'ল"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ল’ড হৈ আছে…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"জীৱন্ত (ডিফ\'ল্ট)"</item>
     <item msgid="8446070607501413455">"প্ৰাকৃতিক"</item>
@@ -422,15 +423,15 @@
     <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"ছিষ্টেমৰ ভাষা ব্যৱহাৰ কৰক"</string>
     <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>ৰ ছেটিংবিলাক খুলিব পৰা নগ\'ল"</string>
     <string name="ime_security_warning" msgid="4135828934735934248">"এই ইনপুট পদ্ধতিটোৱে আপুনি টাইপ কৰা আপোনাৰ ব্যক্তিগত ডেটা যেনে পাছৱৰ্ডসমূহ আৰু ক্ৰেডিট কাৰ্ডৰ নম্বৰসমূহকে ধৰি সকলো পাঠ সংগ্ৰহ কৰিবলৈ সক্ষম হ\'ব পাৰে। <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> এপটোৰ লগত ই সংলগ্ন। এই ইনপুট পদ্ধতিটো ব্যৱহাৰ কৰেনে?"</string>
-    <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"টোকা: ৰিবুট কৰাৰ পিছত আপুনি ফ\'নটো আনলক নকৰালৈকে এই এপটো ষ্টাৰ্ট নহ\'ব"</string>
+    <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"টোকা: ৰিবুট কৰাৰ পিছত আপুনি ফ\'নটো আনলক নকৰালৈকে এই এপটো ষ্টাৰ্ট নহ’ব"</string>
     <string name="ims_reg_title" msgid="7609782759207241443">"আইএমএছ পঞ্জীয়ন স্থিতি"</string>
     <string name="ims_reg_status_registered" msgid="933003316932739188">"পঞ্জীকৃত"</string>
     <string name="ims_reg_status_not_registered" msgid="6529783773485229486">"পঞ্জীকৃত নহয়"</string>
     <string name="status_unavailable" msgid="7862009036663793314">"উপলব্ধ নহয়"</string>
     <string name="wifi_status_mac_randomized" msgid="5589328382467438245">"MAC ক্ৰমানুসৰি ছেট কৰা হোৱা নাই"</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="3871603864314407780">
-      <item quantity="one">%1$dটা ডিভাইচ সংযোগ হ\'ল</item>
-      <item quantity="other">%1$dটা ডিভাইচ সংযোগ হ\'ল</item>
+      <item quantity="one">%1$dটা ডিভাইচ সংযোগ হ’ল</item>
+      <item quantity="other">%1$dটা ডিভাইচ সংযোগ হ’ল</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="1636187409258564291">"অধিক সময়।"</string>
     <string name="accessibility_manual_zen_less_time" msgid="6590887204171164991">"কম সময়।"</string>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্ৰতিবাৰতে সোধক"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"আপুনি অফ নকৰা পর্যন্ত"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"এই মাত্ৰ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"বিকাশকাৰ্য চলি থকা আপডে\'টেড গ্ৰাফিক ড্ৰাইভাৰ ব্যৱহাৰ কৰিবলৈ এপ্ অপ্ট ইন কৰক"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফ’নৰ স্পীকাৰ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 17d0ca6..daa9c8f 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni rezerv parolu ayarlandı"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni parol və parolun təkrarı uyğun gəlmir"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedəkləmə parolu xətası"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yüklənir…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Canlı (defolt)"</item>
     <item msgid="8446070607501413455">"Təbii"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Hər dəfə soruşun"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Deaktiv edənə qədər"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"İndicə"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Qrafik drayverdən istifadə etmək üçün tətbiq seçin"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon spikeri"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 56052d2..44f14df 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Postavljena je nova lozinka rezervne kopije"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i njena potvrda se ne podudaraju"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Postavljanje lozinke rezervne kopije nije uspelo"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitava se…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živopisan (podrazumevano)"</item>
     <item msgid="8446070607501413455">"Prirodan"</item>
@@ -450,6 +451,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uvek pitaj"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogući aplikaciju za korišćenje upravljačkog programa grafičke katice u razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f2c2046..2dcdd37 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Усталяваны новы пароль для рэзервовага капіявання"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новы пароль і яго пацвярджэнне не супадаюць"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Збой пры ўсталёўцы паролю для рэзервовага капіявання"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ідзе загрузка…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Сочны (па змаўчанні)"</item>
     <item msgid="8446070607501413455">"Натуральны"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Заўсёды пытацца"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Пакуль не выключыце"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Зараз"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Выбраная праграма, якая выкарыстоўвае абноўлены драйвер графічнай сістэмы (падчас распрацоўкі)"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Дынамік тэлефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 5b8d6b8..1e2f0f4 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Зададена е нова парола за резервно копие"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата парола и въведената за потвърждаване не съвпадат"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Задаването на парола за резервно копие не бе успешно"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Зарежда се…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ярък (по подразбиране)"</item>
     <item msgid="8446070607501413455">"Естествен"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Да се пита винаги"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"До изключване"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Току-що"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Включване на приложението за използване на актуализирания графичен драйвер в разработка"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Високоговорител на телефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 7efad99..4ec893b 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন ব্যাকআপ পাসওয়ার্ড সেট করুন"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"নতুন পাসওয়ার্ড এবং নিশ্চিতকরণ মিলছে না"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ব্যাকআপ পাসওয়ার্ড সেট করা ব্যর্থ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"লোড হচ্ছে…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ভাইব্রেন্ট (ডিফল্ট)"</item>
     <item msgid="8446070607501413455">"প্রাকৃতিক"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্রতিবার জিজ্ঞেস করা হবে"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"যতক্ষণ না আপনি বন্ধ করছেন"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"এখনই"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ডেভলপমেন্টে আপডেট হওয়া গ্রাফিক্স ড্রাইভার ব্যবহার করতে অ্যাপ বেছে নিন"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফেনের স্পিকার"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 92435f7..a0a0e2a 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za sigurnosnu kopiju je postavljena"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i potvrda se ne podudaraju"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje lozinke za sigurnosnu kopiju"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitavanje…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živopisno (zadano)"</item>
     <item msgid="8446070607501413455">"Prirodan"</item>
@@ -450,6 +451,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prijavi aplikaciju za korištenje ažuriranog grafičkog drajvera u razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 3182f16..0bd6a1b 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"S\'ha definit una contrasenya de seguretat nova"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La contrasenya nova i la confirmació no coincideixen"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error en definir la contrasenya de seguretat"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregant…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (predeterminat)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pregunta sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Fins que no ho desactivis"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ara mateix"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicació activada per utilitzar el controlador de gràfics actualitzat en desenvolupament"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altaveu del telèfon"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 3785433..69c22ec 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pro zálohy je nastaveno"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo se neshoduje s potvrzením hesla."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavení hesla pro zálohy selhalo"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Načítání…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Jasné (výchozí)"</item>
     <item msgid="8446070607501413455">"Přirozené"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pokaždé se zeptat"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokud tuto funkci nevypnete"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Právě teď"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Přihlaste aplikaci k použití vyvíjeného aktualizovaného grafického ovladače"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefonu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index eeeccee..077258a 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -73,8 +73,8 @@
     <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filoverførsel"</string>
     <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Inputenhed"</string>
     <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetadgang"</string>
-    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deling af kontaktpersoner"</string>
-    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Brug til deling af kontaktpersoner"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deling af kontakter"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Brug til deling af kontakter"</string>
     <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling af internetforbindelse"</string>
     <string name="bluetooth_profile_map" msgid="1019763341565580450">"Sms-beskeder"</string>
     <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-adgang"</string>
@@ -102,7 +102,7 @@
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Par"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ACCEPTÉR PARRING"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuller"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parring giver adgang til dine kontaktpersoner og din opkaldshistorik, når enhederne er forbundet."</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parring giver adgang til dine kontakter og din opkaldshistorik, når enhederne er forbundet."</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grund af en forkert pinkode eller adgangsnøgle."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Der kan ikke kommunikeres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -252,7 +252,7 @@
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Hold altid mobildata aktiveret, selv når Wi-Fi er aktiveret (for at skifte hurtigt mellem netværk)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Brug hardwareacceleration ved netdeling, hvis det er muligt"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Vil du tillade USB-fejlretning?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden underretning og læse logdata."</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden notifikation og læse logdata."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Vil du ophæve adgangen til USB-fejlfinding for alle computere, du tidligere har godkendt?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Vil du tillade udviklingsindstillinger?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens apps går ned eller ikke fungerer korrekt."</string>
@@ -316,8 +316,8 @@
     <string name="app_process_limit_title" msgid="4280600650253107163">"Grænse for baggrundsprocesser"</string>
     <string name="show_all_anrs" msgid="4924885492787069007">"Vis ANR-fejl i baggrunden"</string>
     <string name="show_all_anrs_summary" msgid="6636514318275139826">"Vis dialogboksen \"Appen svarer ikke\" for baggrundsapps"</string>
-    <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Vis advarsler om underretningskanal"</string>
-    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Viser en advarsel, når en app sender en underretning uden en gyldig kanal"</string>
+    <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Vis advarsler om notifikationskanal"</string>
+    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Viser en advarsel, når en app sender en notifikation uden en gyldig kanal"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Gennemtving tilladelse til eksternt lager"</string>
     <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Ny adgangskode til sikkerhedskopi er angivet"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ny adgangskode og bekræftelse matcher ikke"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fejl ved angivelse af adgangskode til sikkerhedskopi"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Indlæser…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Klare (standard)"</item>
     <item msgid="8446070607501413455">"Naturlige"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spørg hver gang"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Indtil du deaktiverer"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Lige nu"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Tilvælg en app, der skal bruge den opdaterede grafikdriver under udvikling"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonens højttaler"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 95f7416..c4e03ad 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Neues Sicherungspasswort festgelegt"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Das neue Passwort und die Bestätigung stimmen nicht überein."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fehler beim Festlegen des Sicherungspassworts"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Wird geladen…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Brillant (Standardeinstellung)"</item>
     <item msgid="8446070607501413455">"Natürlich"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Jedes Mal fragen"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Bis zur Deaktivierung"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Gerade eben"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App aktivieren, um den aktualisierten Grafiktreiber in der Entwicklung zu verwenden"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon-Lautsprecher"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 310b6cf..642e862 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Ορίστηκε νέος εφεδρικός κωδικός πρόσβασης"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ο νέος κωδικός πρόσβασης και η επιβεβαίωση δεν ταιριάζουν"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Αποτυχία κατά τον ορισμό εφεδρικού κωδικού πρόσβασης"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Φόρτωση…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ζωντανό (προεπιλογή)"</item>
     <item msgid="8446070607501413455">"Φυσικό"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Να ερωτώμαι κάθε φορά"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Μέχρι την απενεργοποίηση"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Μόλις τώρα"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Επιλέξτε μια εφαρμογή για τη χρήση του ενημερωμένου προγράμματος οδήγησης γραφικών σε ανάπτυξη"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Ηχείο τηλεφώνου"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 5b11d63..0cdfaf2 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index d7ed49a..eda4d1b 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎New backup password set‎‏‎‎‏‎"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎New password and confirmation don’t match‎‏‎‎‏‎"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎Failure setting backup password‎‏‎‎‏‎"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‎Loading…‎‏‎‎‏‎"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎Vibrant (default)‎‏‎‎‏‎"</item>
     <item msgid="8446070607501413455">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎Natural‎‏‎‎‏‎"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎Ask every time‎‏‎‎‏‎"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎Until you turn off‎‏‎‎‏‎"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎Just now‎‏‎‎‏‎"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎Opt in app to use updated graphcis driver in developement‎‏‎‎‏‎"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎Phone speaker‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index ecec63c..bd3d1b7 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de copia de seguridad definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al definir contraseña de copia de seguridad"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (predeterminado)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que lo desactives"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Recién"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar app para que use el controlador de gráficos actualizado en el desarrollo"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index b8fdf30..94f88eb 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de seguridad establecida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al establecer la contraseña de seguridad"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (predeterminado)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que se desactive"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Justo ahora"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar aplicación para usar controlador de gráficos actualizado en desarrollo"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 1246626..31527dc 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Uus varuparool on määratud"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Uus parool ja kinnitus ei ühti"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Varuparooli määramine ebaõnnestus"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laadimine …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ere (vaikeseade)"</item>
     <item msgid="8446070607501413455">"Loomulikud"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Küsi iga kord"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kuni välja lülitate"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Äsja"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lubage rakendus, et kasutada arenduses olevat värskendatud graafikadraiverit"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoni kõlar"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 68b4840..dd77284 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Babeskopiaren pasahitz berria ezarri da"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Pasahitz berria eta berrespena ez datoz bat"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ezin izan da babeskopiaren pasahitza ezarri"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Kargatzen…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Bizia (balio lehenetsia)"</item>
     <item msgid="8446070607501413455">"Naturala"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Galdetu beti"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Desaktibatu arte"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Oraintxe"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Hautatu zein aplikaziorekin erabili nahi duzun garatze-prozesuan dagoen grafikoen kontrolatzaile eguneratua"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonoaren bozgorailua"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 7882b056..57f8960 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"گذرواژه جدید نسخهٔ پشتیبان تنظیم شد"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"گذرواژه جدید و تأیید آن با یکدیگر مطابقت ندارند"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"گذرواژه پشتیبان‌گیری تنظیم نشد"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"بارگیری…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"پرطروات (پیش‌فرض)"</item>
     <item msgid="8446070607501413455">"طبیعی"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"هربار پرسیده شود"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"تا زمانی‌که آن را خاموش کنید"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"هم‌اکنون"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"برنامه انتخاب‌شده برای استفاده از درایور گرافیک به‌روزرسانی‌شده در برنامه‌نویس"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"بلندگوی تلفن"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 1904c4d..922d8d3 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Uusi varasalasana asetettiin"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Uusi salasana ja vahvistus eivät täsmää"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Varasalasanan asetus epäonnistui"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ladataan…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Voimakas (oletus)"</item>
     <item msgid="8446070607501413455">"Luonnollinen"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Kysy aina"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kunnes poistat sen käytöstä"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Äsken"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lisää sovellus käyttämään päivitettyä grafiikkaohjainta kehitysvaiheessa"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Puhelimen kaiutin"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 45b2872..765a80f 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Chargement en cours…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrantes (par défaut)"</item>
     <item msgid="8446070607501413455">"Naturelles"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionnez l\'application pour utiliser le pilote graphique mis à jour en mode de conception"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 13361d7..198b922 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Chargement…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Couleurs éclatantes (par défaut)"</item>
     <item msgid="8446070607501413455">"Couleurs naturelles"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionner une application pour le développement de laquelle utiliser le pilote graphique mis à jour"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index e8cf009..de5e7e41 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo contrasinal da copia de seguranza definido"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"O contrasinal novo e a confirmación non coinciden"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Erro ao definir un contrasinal da copia de seguranza"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Brillante (predeterminado)"</item>
     <item msgid="8446070607501413455">"Naturais"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Ata a desactivación"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Subscribirse á aplicación para utilizar o controlador de gráficos actualizado en desenvolvemento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altofalante do teléfono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 918920d..993eed1 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"નવો બેકઅપ પાસવર્ડ સેટ કર્યો છે"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"નવો પાસવર્ડ અને પુષ્ટિકરણ મેળ ખાતા નથી"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"નિષ્ફળતા સેટિંગ બેકઅપ પાસવર્ડ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"લોડ થઈ રહ્યું છે…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"વાઇબ્રન્ટ (ડિફોલ્ટ)"</item>
     <item msgid="8446070607501413455">"કુદરતી"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"દર વખતે પૂછો"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"તમે બંધ ન કરો ત્યાં સુધી"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"હમણાં જ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"અપડેટ કરેલ ગ્રાફિક્સ ડ્રાઇવરનો ઉપયોગ કરવા માટે અ‍ૅપ પસંદ કરો"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ફોન સ્પીકર"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 890d036..faf551e 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"नया बैकअप पासवर्ड सेट किया गया"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नया पासवर्ड तथा पुष्टि मेल नही खाते"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"सुरक्षित पासवर्ड सेट करने में विफल रहा"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड हो रहा है…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"चमकीला (डिफ़ॉल्ट)"</item>
     <item msgid="8446070607501413455">"स्वाभाविक"</item>
@@ -416,7 +417,7 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"मेन्यू"</string>
     <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोड में फ़ैक्टरी रीसेट के लिए पासवर्ड डालें"</string>
-    <string name="retail_demo_reset_next" msgid="8356731459226304963">"आगे"</string>
+    <string name="retail_demo_reset_next" msgid="8356731459226304963">"आगे बढ़ें"</string>
     <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक"</string>
     <string name="active_input_method_subtypes" msgid="3596398805424733238">"टाइप करने की सक्रीय पद्धतियां"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"सिस्टम की भाषाओं का उपयोग करें"</string>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"डेवलपमेंट में अपडेट किए गए ग्राफ़िक्स ड्राइवर का इस्तेमाल करने के लिए ऐप्लिकेशन में ऑप्ट इन करें"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फ़ोन स्पीकर"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 1464b91..5f04b65 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova zaporka za sigurnosnu kopiju postavljena"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova zaporka i potvrda ne odgovaraju"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje zaporke za sigurnosnu kopiju"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitavanje…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živopisno (zadano)"</item>
     <item msgid="8446070607501413455">"Prirodno"</item>
@@ -450,6 +451,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo sad"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uključi aplikaciju za upotrebu ažuriranog upravljačkog programa u razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index c9fdd45..7469c1a 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Új mentési jelszó beállítva"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Az új jelszó és a megerősítése nem egyezik."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Hiba a mentési jelszó beállítása során"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Betöltés…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Élénk (alapértelmezett)"</item>
     <item msgid="8446070607501413455">"Természetes"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Mindig kérdezzen rá"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kikapcsolásig"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Az imént"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"A frissített, fejlesztés alatt álló grafikus drivert használja a választott alkalmazás"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hangszórója"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 3b13ed1..b27bb7e 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Պահուստավորման նոր գաղտնաբառը սահմանված է"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Նոր գաղտնաբառը և հաստատումը չեն համընկնում"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ձախողում գաղտնաբառի պահուստավորման կարգավորման ընթացքում"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Բեռնում…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Պայծառ (կանխադրված)"</item>
     <item msgid="8446070607501413455">"Բնական"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Հարցնել ամեն անգամ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Մինչև չանջատեք"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Հենց նոր"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ընտրված հավելվածը, որը պետք է օգտագործի թարմացված գրաֆիկական սարքավարը մշակման ժամանակ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Հեռախոսի բարձրախոս"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 4d1b2df..342a505 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Sandi cadangan baru telah disetel"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Sandi baru dan konfirmasinya tidak cocok."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menyetel sandi cadangan"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Memuat…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Terang (default)"</item>
     <item msgid="8446070607501413455">"Alami"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Selalu tanya"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Sampai Anda menonaktifkannya"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Baru saja"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ikut sertakan aplikasi untuk menggunakan driver grafis yang diupdate dalam pengembangan"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ponsel"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 600ffa4..8f1b9a1 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nýtt aðgangsorð fyrir afritun valið"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nýja aðgangsorðið og staðfestingaraðgangsorðið eru ekki eins"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Villa við að velja aðgangsorð fyrir afritun"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Hleður…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Líflegir (sjálfgefið)"</item>
     <item msgid="8446070607501413455">"Náttúrulegir"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spyrja í hvert skipti"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Þar til þú slekkur"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Rétt í þessu"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velja að nota uppfærðan myndefnisrekil í þróun í forriti"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Símahátalari"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 068aa91..6600ca2 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuova password di backup impostata"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le password inserite non corrispondono"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Impossibile impostare la password di backup"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Caricamento…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vivaci (opzione predefinita)"</item>
     <item msgid="8446070607501413455">"Naturali"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Chiedi ogni volta"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Fino alla disattivazione"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Adesso"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Attiva l\'app per utilizzare il driver grafico aggiornato nella versione di sviluppo"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlante telefono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fa38f77..a8da0b1 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"הוגדרה סיסמת גיבוי חדשה"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"הסיסמה החדשה והאישור אינם תואמים"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"הגדרת סיסמת גיבוי נכשלה"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"טוען…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"דינמי (ברירת מחדל)"</item>
     <item msgid="8446070607501413455">"טבעי"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"שאל בכל פעם"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"עד הכיבוי"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"הרגע"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"האפליקציה שנבחרה לשימוש במנהל ההתקן המעודכן לגרפיקה שבפיתוח"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"רמקול של טלפון"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9927654..ea62637 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"新しいバックアップパスワードが設定されました"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新しいパスワードと確認用のパスワードが一致しません。"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"バックアップパスワードの設定に失敗しました"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"読み込んでいます…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"鮮やか(既定)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"毎回確認"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"OFF にするまで"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"たった今"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"更新したグラフィックス ドライバを開発に使用するオプトイン アプリ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"スマートフォンのスピーカー"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 7ba0153..bd88435 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ახალი სარეზერვო პაროლის დაყენება"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ახალი და დადასტურებული პაროლები არ შეესატყვისება ერთმანეთს"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"სარეზერვო პაროლის დაყენება ვერ მოხერხდა"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"მიმდინარეობს ჩატვირთვა…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"მკვეთრი (ნაგულისხმევი)"</item>
     <item msgid="8446070607501413455">"ბუნებრივი"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ყოველთვის მკითხეთ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"გამორთვამდე"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ახლახან"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"გააქტიურების აპი, რომელიც გამოიყენებს შემუშავების პროცესში მყოფ, განახლებულ გრაფიკულ დრაივერს"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ტელეფონის დინამიკი"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index d5b4441..d22b139 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Жаңа сақтық кілтсөзі тағайындалды"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Жаңа кілтсөз және растау сәйкес емес"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Сақтық кілтсөзі тағайындалмады"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Жүктелуде…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Жарқын (әдепкі)"</item>
     <item msgid="8446070607501413455">"Табиғи"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Әрдайым сұрау"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Өшірілгенге дейін"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Дәл қазір"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Әзірлеу барысында қолданба жаңартылған графика драйверін пайдаланады"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефон динамигі"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index d1d1c76..d516db9 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"កំណត់​ពាក្យ​សម្ងាត់​បម្រុង​ទុក​ថ្មី"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ពាក្យ​សម្ងាត់​ថ្មី និង​ការ​បញ្ជាក់​​មិន​ដូច​គ្នា"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"បរាជ័យ​ក្នុង​ការ​កំណត់​ពាក្យ​សម្ងាត់​បម្រុងទុក"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"កំពុងផ្ទុក…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"រស់រវើក (លំនាំដើម)"</item>
     <item msgid="8446070607501413455">"ធម្មជាតិ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"សួរគ្រប់ពេល"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"រហូតទាល់តែ​អ្នកបិទ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"អម្បាញ់មិញ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ភ្ជាប់កម្មវិធី​ ដើម្បី​ប្រើដ្រាយវើ​ក្រាហ្វិក​ដែលបាន​ដំឡើងជំនាន់​សម្រាប់​ការ​អភិវឌ្ឍ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ឧបករណ៍​បំពង​សំឡេង​ទូរសព្ទ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 46759f5..94a711c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ಹೊಸ ಬ್ಯಾಕಪ್ ಪಾಸ್‌ವರ್ಡ್‌ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ಹೊಸ ಪಾಸ್‌ವರ್ಡ್‌ ಮತ್ತು ದೃಢೀಕರಣ ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ಬ್ಯಾಕಪ್‌ ಪಾಸ್‌ವರ್ಡ್‌ ಹೊಂದಿಕೆ ವಿಫಲಗೊಂಡಿದೆ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ಲೋಡ್ ಆಗುತ್ತಿದೆ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ಸ್ಪಂದನಾತ್ಮಕ (ಡೀಫಾಲ್ಟ್)"</item>
     <item msgid="8446070607501413455">"ಪ್ರಾಕೃತಿಕ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ಪ್ರತಿ ಬಾರಿ ಕೇಳಿ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ಇದೀಗ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ಅಭಿವೃದ್ಧಿಯಲ್ಲಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾದ ಗ್ರಾಫಿಕ್‌ಗಳ ಡ್ರೈವರ್ ಬಳಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ಫೋನ್ ಸ್ಪೀಕರ್"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 067175b..0b4125f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"새 백업 비밀번호가 설정되었습니다."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"새 비밀번호와 확인한 비밀번호가 일치하지 않습니다."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"백업 비밀번호를 설정하지 못했습니다."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"로드 중…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"생동감(기본값)"</item>
     <item msgid="8446070607501413455">"내츄럴"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"항상 확인"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"사용 중지할 때까지"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"조금 전"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"개발 중인 업데이트된 그래픽 드라이버를 사용할 앱을 선택하세요."</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"휴대전화 스피커"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 8e994da..42dc97e 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Жаңы бэкапка сырсөз коюулду"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Жаңы сырсөз жана анын ырастоосу дал келген жок"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Жаңы бэкапка сырсөз коюлган жок"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Жүктөлүүдө…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Толкундуу (демейки)"</item>
     <item msgid="8446070607501413455">"Табигый"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ар дайым суралсын"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Бул функция өчүрүлгөнгө чейин"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Азыр эле"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Иштеп чыгууда жаңыртылган графикалык драйверлерди пайдалануу үчүн колдонмону кошуңуз"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефондун динамиги"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 7bf46c0..0505a5d 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ຕັ້ງລະຫັດສຳຮອງໃໝ່ແລ້ວ"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ລະຫັດຜ່ານໃໝ່ ແລະລະຫັດຢືນຢັນບໍ່ກົງກັນ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ການຕັ້ງລະຫັດສຳຮອງຂໍ້ມູນລົ້ມເຫລວ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ກຳລັງໂຫລດ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ຕົວ​ສັ່ນ (ມາດ​ຕະ​ຖານ)"</item>
     <item msgid="8446070607501413455">"ທຳ​ມະ​ຊາດ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ຖາມທຸກເທື່ອ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ຈົນກວ່າທ່ານຈະປິດ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ຕອນນີ້"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ເຂົ້າຮ່ວມແອັບເພື່ອໃຊ້ໄດຣເວີກຣາຟິກທີ່ອັບເດດແລ້ວໃນການພັດທະນາ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ລຳໂພງໂທລະສັບ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 9da3d52..e1412e7 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nustatytas naujas atsarginės kopijos slaptažodis"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Naujas slaptažodis ir patvirtinimas neatitinka"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nustatant atsarginės kopijos slaptažodį įvyko klaida"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Įkeliama…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ryškus (numatytasis)"</item>
     <item msgid="8446070607501413455">"Natūralus"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Klausti kaskart"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kol išjungsite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ką tik"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Pasirinkti programą, kuri bus naudojama su atnaujinta kuriama grafikos tvarkykle"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefono garsiakalbis"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 2233468..5082775 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Jaunā dublējuma parole ir iestatīta."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Jaunā parole un apstiprinājums neatbilst."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Iestatot dublējuma paroli, radās kļūme."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Notiek ielāde…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Spilgts (noklusējums)"</item>
     <item msgid="8446070607501413455">"Dabisks"</item>
@@ -450,6 +451,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vaicāt katru reizi"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Līdz brīdim, kad izslēgsiet"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Tikko"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Izvēlēties izmantot atjaunināto grafikas dzini šīs lietotnes izstrādē"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Tālruņa skaļrunis"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 534d154..99cf468 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Подесена нова лозинка на резервна копија"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата лозинка и потврдата не се исти"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Неуспешно подесување лозинка на резервна копија"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Се вчитува…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Динамично (стандардно)"</item>
     <item msgid="8446070607501413455">"Природно"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Секогаш прашувај"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Додека не го исклучите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Неодамнешни"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Прифатете ја апликацијата за да се користи ажурираниот драјвер за графика во програмирање"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефонски звучник"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 7a335cd..a0222ad 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"പുതിയ ബാക്കപ്പ് പാസ്‌വേഡ് സജ്ജമാക്കി"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"പുതിയ പാസ്‌വേഡും സ്ഥിരീകരണവും പൊരുത്തപ്പെടുന്നില്ല"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ബാക്കപ്പ് പാസ്‌വേഡ് സജ്ജമാക്കുന്നതിൽ പരാജയപ്പെട്ടു"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ലോഡ് ചെയ്യുന്നു…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"വൈബ്രന്റ് (സ്ഥിരമായത്)"</item>
     <item msgid="8446070607501413455">"സ്വാഭാവികം"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"എപ്പോഴും ചോദിക്കുക"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ഇപ്പോൾ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"വികസനത്തിൽ, അപ്ഡേറ്റ് ചെയ്‌ത ഗ്രാഫിക്‌സ് ഡ്രൈവർ ഉപയോഗിക്കാൻ ഓപ്റ്റ് ഇൻ ചെയ്യുക"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ഫോൺ സ്‌പീക്കർ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 4816643..5b2acac 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Нөөцлөлтийн шинэ нууц үг тохирууллаа"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Шинэ нууц үг болон баталгаажуулалт таарахгүй байна"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Нөөшлөлтийн нууц үгийг тохируулахад алдаа гарлаа"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ачаалж байна…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Хурц (үндсэн)"</item>
     <item msgid="8446070607501413455">"Байгалийн"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Тухай бүрт асуух"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Таныг унтраах хүртэл"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Дөнгөж сая"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Хөгжүүлэлтэд буй шинэчилсэн график драйверийг ашиглахын тулд аппад нэгдэх"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Утасны чанга яригч"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 5b09b29..891ada8 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"नवीन बॅक अप पासवर्ड सेट झाला"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नवीन पासवर्ड आणि पुष्टीकरण जुळत नाही"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"बॅक अप पासवर्ड सेट करणे अयशस्वी"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड करत आहे…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"सशक्त (डीफॉल्ट)"</item>
     <item msgid="8446070607501413455">"नैसर्गिक"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक वेळी विचारा"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"तुम्ही बंद करेपर्यंत"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"आत्ताच"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"अपडेट केलेले ग्राफिक ड्राइव्हर डेव्हलमेंटमध्ये वापरण्यासाठी अ‍ॅप निवडा"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनचा स्पीकर"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 3593882..8030c3e 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Kata laluan sandaran baharu telah ditetapkan"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Kata laluan baharu dan pengesahan tidak sepadan"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menetapkan kata laluan sandaran"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Memuatkan…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Terang (lalai)"</item>
     <item msgid="8446070607501413455">"Semula Jadi"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Tanya setiap kali"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Sehingga anda matikan"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sebentar tadi"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sertakan apl untuk menggunakan pemacu grafik yang dikemas kini dalam pembangunan"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Pembesar suara telefon"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7ac3742..c543974 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်အသစ်ကို သတ်မှတ်ပြီးပြီ။"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"စကားဝှက်အသစ်နှင့် အတည်ပြုချက် ကွဲလွဲနေသည်။"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်သတ်မှတ်ချက် မအောင်မြင်ပါ။"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ဖွင့်နေသည်…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"တက်ကြွခြင်း (မူလ)"</item>
     <item msgid="8446070607501413455">"သဘာဝ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"အမြဲမေးပါ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"သင်ပိတ်လိုက်သည် အထိ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ယခုလေးတင်"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ဆော့ဖ်ဝဲရေးဆွဲမှုအတွင်း အပ်ဒိတ်လုပ်ထားသော ဂရပ်ဖစ်ဒရိုင်ဗာကို အသုံးပြုရန် အက်ပ်ကို ရွေးချယ်ပါ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ဖုန်းစပီကာ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index e810ba2..c4ad033 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nytt passord for sikkerhetskopiering er angitt."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Gjentakelsen av passordet er ikke identisk med det første du skrev inn"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Kunne ikke angi nytt passord for sikkerhetskopiering"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laster inn …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Krystallklar (standard)"</item>
     <item msgid="8446070607501413455">"Naturlig"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spør hver gang"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Til du slår av"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Nå nettopp"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velg app for å bruke en oppdatert grafikkdriver som er under utvikling"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonhøyttaler"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 0b4510fd..f67e05c 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -231,7 +231,7 @@
     <string name="private_dns_mode_off" msgid="8236575187318721684">"निष्क्रिय छ"</string>
     <string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"स्वचालित"</string>
     <string name="private_dns_mode_provider" msgid="8354935160639360804">"निजी DNS प्रदायकको होस्टनाम"</string>
-    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS प्रदायकको होस्टनाम प्रविष्ट गर्नुहोस्"</string>
+    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS प्रदायकको होस्टनाम प्रविष्टि गर्नुहोस्"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"जडान गर्न सकिएन"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"नयाँ जगेडा पासवर्ड सेट गर्नुहोस्"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नयाँ पासवर्ड र पुष्टिकरण मेल खाँदैनन्"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"विफलता सेटिङ ब्याकअप पासवर्ड"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड गर्दै…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"जोसिलो (पूर्व निर्धारित)"</item>
     <item msgid="8446070607501413455">"प्राकृतिक"</item>
@@ -415,7 +416,7 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"आफू अनुकूल (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
-    <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्ट गर्नुहोस्"</string>
+    <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्टि गर्नुहोस्"</string>
     <string name="retail_demo_reset_next" msgid="8356731459226304963">"अर्को"</string>
     <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक छ"</string>
     <string name="active_input_method_subtypes" msgid="3596398805424733238">"आगत विधिहरू सक्रिय गर्नुहोस्"</string>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक पटक सोध्नुहोस्"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"तपाईंले निष्क्रिय नपार्दासम्म"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"अहिले भर्खरै"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"विकासको क्रममा अद्यावधिक गरिएको ग्राफिक ड्राइभर प्रयोग गर्न अप्ट इन गर्नुहोस्"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनको स्पिकर"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f227e1c..d2fd4e24 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -236,7 +236,7 @@
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
     <string name="wifi_connected_mac_randomization_summary" msgid="1743059848752201485">"Een willekeurig MAC-adres bij het maken van verbinding met wifi-netwerken"</string>
-    <string name="wifi_metered_label" msgid="4514924227256839725">"Betaald"</string>
+    <string name="wifi_metered_label" msgid="4514924227256839725">"Met datalimiet"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"Gratis"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"Logger-buffergrootten"</string>
     <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Kies Logger-grootten per logbuffer"</string>
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nieuw back-upwachtwoord ingesteld"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nieuw wachtwoord en bevestiging komen niet overeen."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Instellen van back-upwachtwoord is mislukt"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laden…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Levendig (standaard)"</item>
     <item msgid="8446070607501413455">"Natuurlijk"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Altijd vragen"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat je uitschakelt"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Zojuist"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Meld een app aan om het geüpdatete grafische stuurprogramma in ontwikkeling te gebruiken"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoonluidspreker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index bf8493a..bed22a7 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ନୂଆ ବ୍ୟାକ୍‌ଅପ୍‌ ପାସ୍‌ୱର୍ଡ ସେଟ୍‌ କରିଦିଆଗଲା"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ନୂଆ ପାସ୍‌ୱର୍ଡ ଓ ସୁନିଶ୍ଚିତତା ମେଳ ହେଉନାହିଁ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ବ୍ୟାକ୍‌ଅପ୍‌ ପାସ୍‌ୱର୍ଡ ସେଟିଙ୍ଗ ବିଫଳ ହୋଇଛି"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ଲୋଡ୍ ହେଉଛି…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ଜୀବନ୍ତ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ)"</item>
     <item msgid="8446070607501413455">"ପ୍ରାକୃତିକ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ DND ଅନ୍‌ ରହିବ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ଏହିକ୍ଷଣି"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ଡେଭଲପ୍‍‍‍‍‍‍‍‍ମେଣ୍ଟରେ ଅପ୍‍‍‍‍‍‍‍ଡେଟ୍‍ ଗ୍ରାଫିକ୍ସ ଡ୍ରାଇଭର୍‍ ବ୍ୟବହାର କରିବାକୁ ଆପ୍ଟ ଇ‍ନ୍‍ ଅପ୍ଲିକେସନ୍‍"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ଫୋନ୍‍ ସ୍ପିକର୍‍"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index f948a7e..1c2a947 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ਨਵਾਂ ਬੈਕਅੱਪ ਪਾਸਵਰਡ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ਨਵਾਂ ਪਾਸਵਰਡ ਅਤੇ ਪੁਸ਼ਟੀ ਮੇਲ ਨਹੀਂ ਖਾਂਦੀ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ਬੈਕਅੱਪ ਪਾਸਵਰਡ ਸੈੱਟ ਕਰਨ ਵਿੱਚ ਅਸਫਲਤਾ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ਚਮਕੀਲਾ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
     <item msgid="8446070607501413455">"ਕੁਦਰਤੀ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ਹੁਣੇ ਹੀ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ਅੱਪਡੇਟ ਕੀਤੇ ਵਿਕਾਸ-ਅਧੀਨ ਗ੍ਰਾਫਿਕਸ ਡਰਾਈਵਰ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਐਪ ਦੀ ਚੋਣ ਕਰੋ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index c75a894..1a0a30d 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nowe hasło kopii zapasowej zostało ustawione"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nowe hasła nie pasują do siebie"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nie udało się ustawić hasła kopii zapasowej"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ładuję…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Żywe (domyślnie)"</item>
     <item msgid="8446070607501413455">"Naturalne"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Zawsze pytaj"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dopóki nie wyłączysz"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Przed chwilą"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Wybierz aplikację, która ma używać opracowywanego sterownika grafiki"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Głośnik telefonu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index c273f59..2795d47 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova senha de backup definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova senha e a confirmação não coincidem."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha ao definir a senha de backup"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (padrão)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 26e4729..fd15210 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova palavra-passe da cópia de segurança definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova palavra-passe e a confirmação não coincidem"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha na definição da palavra-passe da cópia de segurança"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"A carregar…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (predefinição)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até ser desativado"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Optar pela aplicação para utilizar a placa gráfica atualizada em desenvolvimento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altifalante do telemóvel"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index c273f59..2795d47 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova senha de backup definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova senha e a confirmação não coincidem."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha ao definir a senha de backup"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (padrão)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 94f4842..ecdd003 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"A fost setată o parolă de rezervă nouă"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parola nouă și confirmarea acesteia nu se potrivesc."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Setarea parolei de rezervă a eșuat"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Se încarcă…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (prestabilit)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -450,6 +451,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Întreabă de fiecare dată"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Până când dezactivați"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Chiar acum"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicația pentru înscriere pentru a folosi driverul actualizat al plăcii grafice este în dezvoltare"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Difuzorul telefonului"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 1c331d8..74075c5 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Новый пароль для резервной копии установлен"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Пароли не совпадают"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Не удалось установить пароль для резервной копии"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Загрузка…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Насыщенный (по умолчанию)"</item>
     <item msgid="8446070607501413455">"Естественный"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Всегда спрашивать"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Пока вы не отключите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Только что"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Приложение будет использовать обновленный драйвер графической системы (на стадии разработки)"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Встроенный динамик"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 608ff7f..fc90db5 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"නව උපස්ථ මුරපදය සකසන ලදි"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"නව මුරපදය සහ සත්‍යාපනය නොගැළපුනි"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"උපස්ථ මුරපදය පිහිටුවීම අසාර්ථකය"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"පූරණය වේ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"දීප්තිමත් (පෙරනිමිය)"</item>
     <item msgid="8446070607501413455">"ස්වභාවික"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"සෑම විටම ඉල්ලන්න"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ඔබ ක්‍රියාවිරහිත කරන තුරු"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"මේ දැන්"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"වැඩිදියුණු වෙමින් ඇති යාවත්කාලීන කළ චිත්‍රක ධාවකය භාවිත කිරීමට යෙදුමට ඇතුළු වන්න"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"දුරකථන ස්පීකරය"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 2f76ef9..ed51f55 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pre zálohy je nastavené"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo a potvrdenie sa nezhodujú"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavenie hesla pre zálohy zlyhalo"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Načítava sa…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Sýty (predvolený)"</item>
     <item msgid="8446070607501413455">"Prirodzený"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vždy sa opýtať"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokiaľ túto funkciu nevypnete"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Teraz"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prihlásiť aplikáciu, ktorá má používať aktualizovaný ovládač grafickej karty vo vývoji"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefónu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 64124cb..ad47f75 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo geslo je nastavljeno"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Novo geslo in potrditev se ne ujemata."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavitev gesla ni uspela"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Nalaganje …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živo (privzeto)"</item>
     <item msgid="8446070607501413455">"Naravno"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vedno vprašaj"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokler ne izklopite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Pravkar"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogočena aplikacija za uporabo posodobljenega grafičnega gonilnika pri razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvočnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 25d575e..f8f491b 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Fjalëkalimi i ri u vendos"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Fjalëkalimi i ri dhe konfirmimi nuk përputhen"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Vendosja e fjalëkalimit dështoi"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Po ngarkohet…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Të gjalla (parazgjedhja)"</item>
     <item msgid="8446070607501413455">"Natyrale"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pyet çdo herë"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Deri sa ta çaktivizosh"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Pikërisht tani"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prano aplikacionin për të përdorur drejtuesin e përditësuar të grafikës që është në zhvillim"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlanti i telefonit"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index b58b47c..3fe40f9 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Постављена је нова лозинка резервне копије"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Нова лозинка и њена потврда се не подударају"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Постављање лозинке резервне копије није успело"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Учитава се…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Живописан (подразумевано)"</item>
     <item msgid="8446070607501413455">"Природан"</item>
@@ -450,6 +451,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Увек питај"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Док не искључите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Управо"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Омогући апликацију за коришћење управљачког програма графичке катице у развоју"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Звучник телефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7198b84..186395e 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Ett nytt lösenord har angetts"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Det nya lösenordet och bekräftelsen stämmer inte överens"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Det gick inte att ange lösenordet"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Läser in …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Starka (standard)"</item>
     <item msgid="8446070607501413455">"Naturliga"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Fråga varje gång"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Tills du inaktiverar funktionen"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Nyss"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Välj om appen ska använda den uppdaterade grafikdrivrutinen under utveckling"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Mobilens högtalare"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 657b54f..03e0c3a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nenosiri jipya la hifadhi rudufu limewekwa"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nenosiri jipya na uthibitisho havioani"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Imeshindwa kuweka nenosiri la hifadhi rudufu"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Inapakia…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Maridadi (chaguomsingi)"</item>
     <item msgid="8446070607501413455">"Asili"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uliza kila wakati"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hadi utakapoizima"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sasa hivi"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chagua programu itakayotumia kiendeshaji cha michoro kilichosasishwa katika hatua ya kusanidi"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Spika ya simu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 59b42d8..0efd285 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"புதிய காப்புப் பிரதியின் கடவுச்சொல் அமைக்கப்பட்டது"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"புதிய கடவுச்சொல்லும், உறுதிப்படுத்தலுக்கான கடவுச்சொல்லும் பொருந்தவில்லை"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"காப்புப் பிரதி கடவுச்சொல்லை அமைப்பதில் தோல்வி"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ஏற்றுகிறது…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"வைபிரன்ட் (இயல்பு)"</item>
     <item msgid="8446070607501413455">"இயற்கை வண்ணம்"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ஒவ்வொரு முறையும் கேள்"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ஆஃப் செய்யும் வரை"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"சற்றுமுன்"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"உருவாக்கத்திலுள்ள புதுப்பிக்கப்பட்ட கிராஃபிக்ஸ் டிரைவரைப் பயன்படுத்த ஆப்ஸைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"மொபைல் ஸ்பீக்கர்"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index af233da..2caa2ef 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"కొత్త బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేసారు"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"కొత్త పాస్‌వర్డ్ మరియు నిర్ధారణ సరిపోలడం లేదు"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేయడంలో వైఫల్యం"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"లోడ్ చేస్తోంది…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"సచేతనం (డిఫాల్ట్)"</item>
     <item msgid="8446070607501413455">"సహజం"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ప్రతిసారి అడుగు"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"మీరు ఆఫ్‌ చేసే వరకు"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ఇప్పుడే"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"అభివృద్దిలో అప్‌డేట్‌ చేసిన గ్రాఫిక్ డ్రైవర్‌ను ఉపయోగించడానికి యాప్‌ని ప్రారంభించండి"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ఫోన్ స్పీకర్"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 636c3f2..03bf354 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ตั้งรหัสผ่านสำหรับการสำรองข้อมูลใหม่แล้ว"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"รหัสผ่านใหม่และการพิมพ์ยืนยันไม่ตรงกัน"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ไม่สามารถตั้งรหัสผ่านสำหรับการสำรองข้อมูล"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"กำลังโหลด…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"สด (ค่าเริ่มต้น)"</item>
     <item msgid="8446070607501413455">"ธรรมชาติ"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ถามทุกครั้ง"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"จนกว่าคุณจะปิด"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"เมื่อสักครู่"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"เลือกใช้แอปเพื่อใช้ไดรเวอร์กราฟิกที่อัปเดตในการพัฒนา"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ลำโพงโทรศัพท์"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 1bcc36a..3f5cca2 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Naitakda ang bagong backup na password"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Hindi tugma ang password at kumpirmasyon"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nabigo sa pagtatakda ng backup na password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Naglo-load…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Magtanong palagi"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hanggang sa i-off mo"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ngayon lang"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App sa pag-opt in para magamit ang na-update na graphics driver na ginagawa"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ng telepono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index ff669f6..b0a782a 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni yedekleme şifresi ayarlandı"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni şifre ve onayı eşleşmiyor."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedekleme şifresi ayarlanamadı"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yükleniyor…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Canlı (varsayılan)"</item>
     <item msgid="8446070607501413455">"Doğal"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Her zaman sor"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Siz kapatana kadar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Az önce"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Güncellenmiş grafik sürücüsünü geliştirme ortamında kullanmak için uygulamayı kaydedin"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hoparlörü"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 2ded8c1..2b63573 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Новий пароль резервної копії встановлено"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Паролі не збігаються"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Не вдалося зберегти пароль"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Завантаження…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Насичений (за умовчанням)"</item>
     <item msgid="8446070607501413455">"Природний"</item>
@@ -451,6 +452,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Запитувати щоразу"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Доки ви не вимкнете"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Щойно"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Вибраний додаток, який використовуватиме оновлений графічний драйвер під час розробки"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Динамік телефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7dc4690..d7123a6 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"بیک اپ کا نیا پاس ورڈ سیٹ کر دیا گیا"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"نیا پاس ورڈ اور تصدیق مماثل نہیں ہے"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"بیک اپ پاس ورڈ ترتیب دینے میں ناکامی"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"لوڈ ہو رہی ہے…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"پرجوش (ڈیفالٹ)"</item>
     <item msgid="8446070607501413455">"قدرتی"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ہر بار پوچھیں"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"یہاں تک کہ آپ آف کر دیں"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ابھی ابھی"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ڈیولپمنٹ میں اپ ڈیٹ کردہ گرافکس ڈرائیور کو استعمال کرنے کے لیے ایپ آپٹ ان کریں"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"فون اسپیکر"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 5f92c9a..51156d7 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Yangi zaxira paroli o‘rnatildi"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parollar bir-biriga mos kelmadi"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Zaxira parolini o‘rnatib bo‘lmadi"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yuklanmoqda…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Yorqin (birlamchi)"</item>
     <item msgid="8446070607501413455">"Tabiiy"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Har safar so‘ralsin"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Bekor qilinmaguncha"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Hozir"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ilova yangilangan grafik drayverdan (hali ishlov jarayonida) foydalanadi"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon karnayi"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index eb10fb1..13a9322 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Đã đặt mật khẩu sao lưu mới"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Mật khẩu mới và xác nhận không khớp"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Đặt mật khẩu sao lưu không thành công"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Đang tải…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Sống động (mặc định)"</item>
     <item msgid="8446070607501413455">"Tự nhiên"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Luôn hỏi"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Cho đến khi bạn tắt"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Vừa xong"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chọn ứng dụng để sử dụng trình điều khiển đồ họa được cập nhật trong giai đoạn phát triển"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Loa điện thoại"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 7b14138..866c143 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"已设置了新的备份密码"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密码和确认密码不一致"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"设置备份密码失败"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"正在加载…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"鲜亮(默认)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都询问"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"直到您将其关闭"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"刚刚"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"为应用启用更新后的显卡驱动,以在开发过程中使用"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手机扬声器"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 48b6959..f63ba3a 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"已設定新備份密碼"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密碼與確認密碼不符"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"無法設定備份密碼"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"正在載入…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"生動 (預設)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"直至您關閉為止"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"請選取應用程式,以在開發階段使用更新的顯示卡驅動程式"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 684569b..93592a79 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"已設定新備份密碼"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密碼與確認密碼不符。"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"無法設定備份密碼"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"載入中…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"鮮活 (預設)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"直到你關閉為止"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"選取要在開發階段使用最新版繪圖驅動程式的應用程式"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index d107a5a..dd2f3d8 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -330,6 +330,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Iphasiwedi entsha eyisipele isethiwe"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Iphasiwedi entsha nokuqinisekisa akufani"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ukungaphumeleli kokusetha iphasiwedi eyisipele"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Iyalayisha…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Dlidlizela (okuzenzakalelayo)"</item>
     <item msgid="8446070607501413455">"Kwemvelo"</item>
@@ -449,6 +450,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Buza njalo"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Uze uvale isikrini"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Khona manje"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uhlelo lokusebenza lokukhetha ukungena olungasebenzisa idrayivu yamagrafikhi ekuthuthukiseni"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Isipikha sefoni"</string>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 419273e..bcf37ff 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1557,6 +1557,10 @@
                 Settings.Global.ZRAM_ENABLED,
                 GlobalSettingsProto.ZRAM_ENABLED);
 
+        dumpSetting(s, p,
+                Global.APP_OPS_CONSTANTS,
+                GlobalSettingsProto.APP_OPS_CONSTANTS);
+
         p.end(token);
         // Please insert new settings using the same order as in GlobalSettingsProto.
 
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bff2c84..fa95bf2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -134,6 +134,8 @@
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
     <uses-permission android:name="android.permission.MANAGE_CONTENT_CAPTURE" />
+    <uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
     <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.SET_TIME" />
@@ -162,6 +164,8 @@
     <uses-permission android:name="android.permission.SUSPEND_APPS" />
     <uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
 
+    <uses-permission android:name="android.permission.MANAGE_APPOPS" />
+
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
diff --git a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
index d041556..0c6d57d 100644
--- a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
@@ -18,7 +18,7 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <solid android:color="?android:attr/colorBackgroundFloating" />
-    <corners android:radius="1dp"
+    <corners
         android:topLeftRadius="@dimen/biometric_dialog_corner_size"
         android:topRightRadius="@dimen/biometric_dialog_corner_size"
         android:bottomLeftRadius="@dimen/biometric_dialog_corner_size"
diff --git a/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml b/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml
new file mode 100644
index 0000000..26bf981
--- /dev/null
+++ b/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml
@@ -0,0 +1,32 @@
+<?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
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="?android:attr/colorBackgroundFloating"/>
+            <corners
+                    android:topLeftRadius="@dimen/corner_size"
+                    android:topRightRadius="@dimen/corner_size"/>
+        </shape>
+    </item>
+    <item android:gravity="bottom">
+        <shape>
+            <size android:height="1dp"/>
+            <solid android:color="?android:attr/textColorSecondary" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml
index e52aa14..b9b1bb1 100644
--- a/packages/SystemUI/res/layout/battery_percentage_view.xml
+++ b/packages/SystemUI/res/layout/battery_percentage_view.xml
@@ -22,7 +22,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:singleLine="true"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
         android:textColor="?android:attr/textColorPrimary"
         android:gravity="center_vertical|start"
         android:paddingStart="@dimen/battery_level_padding_start"
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
index b2307e7..1aeb52c 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -20,11 +20,23 @@
     android:layout_width="match_parent"
     android:id="@+id/bubble_expanded_view">
 
-    <!-- TODO: header -->
-
     <View
         android:id="@+id/pointer_view"
         android:layout_width="@dimen/bubble_pointer_width"
         android:layout_height="@dimen/bubble_pointer_height"
     />
+
+    <TextView
+        android:id="@+id/bubble_content_header"
+        android:background="@drawable/bubble_expanded_header_bg"
+        android:textAppearance="@*android:style/TextAppearance.Material.Title"
+        android:textSize="18sp"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/bubble_expanded_header_height"
+        android:gravity="start|center_vertical"
+        android:singleLine="true"
+        android:paddingLeft="@dimen/bubble_expanded_header_horizontal_padding"
+        android:paddingRight="@dimen/bubble_expanded_header_horizontal_padding"
+    />
+
 </com.android.systemui.bubbles.BubbleExpandedViewContainer>
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 2000104..74002ac 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -51,11 +51,4 @@
         android:layout_width="wrap_content"
         android:paddingEnd="2dp" />
 
-    <TextView
-        android:id="@+id/batteryRemainingText"
-        android:textAppearance="@style/TextAppearance.QS.TileLabel"
-        android:layout_height="match_parent"
-        android:layout_width="wrap_content"
-        android:gravity="center_vertical" />
-
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
index 307b538..5bcc1b3 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
@@ -39,7 +39,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_title_device_owned"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
@@ -64,7 +64,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_subtitle_ca_certificate"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
@@ -89,7 +89,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_subtitle_network_logging"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
@@ -114,7 +114,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_subtitle_vpn"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 22b8d2f..cd9f780 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -24,6 +24,7 @@
     android:clipToPadding="false"
     android:gravity="center"
     android:orientation="horizontal"
+    android:clickable="true"
     android:paddingStart="@dimen/status_bar_padding_start"
     android:paddingEnd="@dimen/status_bar_padding_end" >
 
@@ -63,11 +64,5 @@
 
     <include layout="@layout/ongoing_privacy_chip" />
 
-    <com.android.systemui.BatteryMeterView
-        android:id="@+id/battery"
-        android:layout_height="match_parent"
-        android:layout_width="wrap_content"
-        android:gravity="center_vertical|end"
-        android:layout_gravity="center_vertical|end" />
     </LinearLayout>
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
deleted file mode 100644
index cfa372b..0000000
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2011, 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.
-*/
--->
-<!-- extends LinearLayout -->
-<com.android.systemui.statusbar.SignalClusterView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/signal_cluster"
-    android:layout_height="match_parent"
-    android:layout_width="wrap_content"
-    android:gravity="center_vertical"
-    android:orientation="horizontal"
-    android:paddingEnd="@dimen/signal_cluster_battery_padding"
-    >
-    <ImageView
-        android:id="@+id/vpn"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:paddingEnd="6dp"
-        android:src="@drawable/stat_sys_vpn_ic"
-        android:tint="@color/background_protect_secondary"
-        android:contentDescription="@string/accessibility_vpn_on"
-        />
-    <FrameLayout
-        android:id="@+id/ethernet_combo"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        >
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/lightIconTheme"
-            android:id="@+id/ethernet"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            />
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/darkIconTheme"
-            android:id="@+id/ethernet_dark"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:alpha="0.0"
-            />
-    </FrameLayout>
-    <FrameLayout
-        android:layout_height="17dp"
-        android:layout_width="wrap_content">
-        <ImageView
-            android:id="@+id/wifi_in"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:src="@drawable/ic_activity_down"
-            android:visibility="gone"
-            android:paddingEnd="2dp"
-            />
-        <ImageView
-            android:id="@+id/wifi_out"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:src="@drawable/ic_activity_up"
-            android:paddingEnd="2dp"
-            android:visibility="gone"
-            />
-    </FrameLayout>
-    <FrameLayout
-        android:id="@+id/wifi_combo"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        >
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/lightIconTheme"
-            android:id="@+id/wifi_signal"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            />
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/darkIconTheme"
-            android:id="@+id/wifi_signal_dark"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:alpha="0.0"
-            />
-        <ImageView
-            android:id="@+id/wifi_inout"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            />
-    </FrameLayout>
-    <View
-        android:id="@+id/wifi_signal_spacer"
-        android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
-        android:layout_height="4dp"
-        android:visibility="gone"
-        />
-    <ViewStub
-        android:id="@+id/connected_device_signals_stub"
-        android:layout="@layout/connected_device_signal"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-    <LinearLayout
-        android:id="@+id/mobile_signal_group"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        >
-    </LinearLayout>
-    <View
-        android:id="@+id/wifi_airplane_spacer"
-        android:layout_width="@dimen/status_bar_airplane_spacer_width"
-        android:layout_height="4dp"
-        android:visibility="gone"
-        />
-    <ImageView
-        android:id="@+id/airplane"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        />
-</com.android.systemui.statusbar.SignalClusterView>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 34c208a..02062bb 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -43,6 +43,14 @@
                    android:visibility="invisible" />
     </com.android.systemui.statusbar.BackDropView>
 
+    <com.android.systemui.wallpaper.AodMaskView
+        android:id="@+id/aod_mask"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:importantForAccessibility="no"
+        android:visibility="invisible"
+        sysui:ignoreRightInset="true" />
+
     <com.android.systemui.statusbar.ScrimView
         android:id="@+id/scrim_behind"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index eed44dd..de2a950 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors is af"</string>
     <string name="device_services" msgid="1191212554435440592">"Toesteldienste"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Titelloos"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7c09112..4154643 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ዳሳሾች ጠፍተዋል"</string>
     <string name="device_services" msgid="1191212554435440592">"የመሣሪያ አገልግሎቶች"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ርዕስ የለም"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 16abb68..579964d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -914,6 +914,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"إيقاف أجهزة الاستشعار"</string>
     <string name="device_services" msgid="1191212554435440592">"خدمات الأجهزة"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"بلا عنوان"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 25f7b5b..8113504 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g>টা অন্য এপ্</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ছেন্সৰ অফ হৈ আছে"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ডিভাইচ সেৱা"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"কোনো শিৰোনাম নাই"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4cc91d2..6a27dbb 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -176,7 +176,7 @@
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Няма SIM-карты."</string>
     <string name="accessibility_cell_data" msgid="5326139158682385073">"Мабільная перадача даных"</string>
     <string name="accessibility_cell_data_on" msgid="5927098403452994422">"Мабільная перадача даных уключана"</string>
-    <string name="cell_data_off_content_description" msgid="4356113230238585072">"Мабільны інтэрнэт выключаны"</string>
+    <string name="cell_data_off_content_description" msgid="4356113230238585072">"Мабільная перадача даных выключана"</string>
     <string name="cell_data_off" msgid="1051264981229902873">"Выключаны"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Сувязь па Bluetooth."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Рэжым палёту."</string>
@@ -865,7 +865,7 @@
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Замяніць"</string>
     <string name="running_foreground_services_title" msgid="381024150898615683">"Праграмы, якія працуюць у фонавым рэжыме"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Дакраніцеся, каб даведацца пра выкарыстанне трафіка і акумулятара"</string>
-    <string name="mobile_data_disable_title" msgid="1068272097382942231">"Адключыць мабільны інтэрнэт?"</string>
+    <string name="mobile_data_disable_title" msgid="1068272097382942231">"Выключыць мабільную перадачу даных?"</string>
     <string name="mobile_data_disable_message" msgid="4756541658791493506">"У вас не будзе доступу да даных ці інтэрнэту праз аператара <xliff:g id="CARRIER">%s</xliff:g>. Інтэрнэт будзе даступны толькі праз Wi-Fi."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"ваш аператар"</string>
     <string name="touch_filtered_warning" msgid="8671693809204767551">"Праграма хавае запыт на дазвол, таму ваш адказ немагчыма спраўдзіць у Наладах."</string>
@@ -904,6 +904,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчыкі выкл."</string>
     <string name="device_services" msgid="1191212554435440592">"Сэрвісы прылады"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Без назвы"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ede7af9..e9effcf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите са изключени"</string>
     <string name="device_services" msgid="1191212554435440592">"Услуги за устройството"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Няма заглавие"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 76a344f..0724e37 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"সেন্সর বন্ধ"</string>
     <string name="device_services" msgid="1191212554435440592">"ডিভাইস সংক্রান্ত পরিষেবা"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"কোনও শীর্ষক নেই"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 69550b0..4e8e833 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors desactivats"</string>
     <string name="device_services" msgid="1191212554435440592">"Serveis per a dispositius"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sense títol"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index cf116e3..30bf1de 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -902,6 +902,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory jsou vypnuty"</string>
     <string name="device_services" msgid="1191212554435440592">"Služby zařízení"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ce9a821..ad4afcf 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -21,9 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"System-UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ryd"</string>
-    <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen underretninger"</string>
+    <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen notifikationer"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
-    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
+    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifikationer"</string>
     <string name="battery_low_title" msgid="9187898087363540349">"Enheden løber muligvis snart tør for batteri"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
     <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Der er <xliff:g id="PERCENTAGE">%1$s</xliff:g> tilbage eller ca. <xliff:g id="TIME">%2$s</xliff:g>, alt efter hvordan du bruger enheden"</string>
@@ -41,7 +41,7 @@
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatisk skærmrotation"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"LYDLØS"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Underretninger"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifikationer"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Netdeling via Bluetooth anvendt"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inputmetoder"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
@@ -71,7 +71,7 @@
     <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Screenshottet kan ikke gemmes, fordi der er begrænset lagerplads"</string>
     <string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Appen eller din organisation tillader ikke, at du tager screenshots"</string>
     <string name="screenrecord_name" msgid="4196719243134204796">"Skærmoptagelse"</string>
-    <string name="screenrecord_channel_description" msgid="4630777331970993858">"Konstant underretning om skærmoptagelse"</string>
+    <string name="screenrecord_channel_description" msgid="4630777331970993858">"Konstant notifikation om skærmoptagelse"</string>
     <string name="screenrecord_start_label" msgid="5177739269492196055">"Start optagelse"</string>
     <string name="screenrecord_mic_label" msgid="4522870600914810019">"Optag voiceover"</string>
     <string name="screenrecord_taps_label" msgid="1776467076607964790">"Vis tryk"</string>
@@ -187,9 +187,9 @@
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batteri <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
     <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batteriet oplades. <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systemindstillinger."</string>
-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Underretninger."</string>
-    <string name="accessibility_overflow_action" msgid="5681882033274783311">"Se alle underretninger"</string>
-    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ryd underretning."</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifikationer."</string>
+    <string name="accessibility_overflow_action" msgid="5681882033274783311">"Se alle notifikationer"</string>
+    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ryd notifikation."</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS aktiveret."</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS samler data."</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter aktiveret."</string>
@@ -199,8 +199,8 @@
     <skip />
     <!-- no translation found for accessibility_work_mode (702887484664647430) -->
     <skip />
-    <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
-    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Underretningspanel."</string>
+    <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifikationen er annulleret."</string>
+    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notifikationspanel."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hurtige indstillinger."</string>
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låseskærm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Indstillinger"</string>
@@ -265,14 +265,14 @@
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string>
-    <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle underretninger."</string>
+    <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle notifikationer."</string>
     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> mere"</string>
     <string name="notification_group_overflow_indicator_ambient" msgid="879560382990377886">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, +<xliff:g id="OVERFLOW">%2$s</xliff:g>"</string>
     <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
-      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> underretning mere i gruppen.</item>
-      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> underretninger mere i gruppen.</item>
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> notifikation mere i gruppen.</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> notifikationer mere i gruppen.</item>
     </plurals>
-    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Underretningsindstillinger"</string>
+    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Notifikationsindstillinger"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Indstillinger for <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
@@ -347,7 +347,7 @@
       <item quantity="one">%d enhed</item>
       <item quantity="other">%d enheder</item>
     </plurals>
-    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Underretninger"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifikationer"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lommelygte"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobildata"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Dataforbrug"</string>
@@ -382,7 +382,7 @@
     <string name="zen_silence_introduction_voice" msgid="3948778066295728085">"Dette blokerer ALLE lyde og vibrationer, bl.a. fra alarmer, musik, videoer og spil. Du vil stadig kunne foretage telefonopkald."</string>
     <string name="zen_silence_introduction" msgid="3137882381093271568">"Dette blokerer ALLE lyde og vibrationer, bl.a. fra alarmer, musik, videoer og spil."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
-    <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende underretninger nedenfor"</string>
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende notifikationer nedenfor"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg opad for at låse op"</string>
     <string name="do_disclosure_generic" msgid="5615898451805157556">"Denne enhed administreres af din organisation"</string>
@@ -439,9 +439,9 @@
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Ryd alt"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Administrer"</string>
-    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Underretninger er sat på pause af Forstyr ikke"</string>
+    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifikationer er sat på pause af Forstyr ikke"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start nu"</string>
-    <string name="empty_shade_text" msgid="708135716272867002">"Ingen underretninger"</string>
+    <string name="empty_shade_text" msgid="708135716272867002">"Ingen notifikationer"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåges"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Netværket kan være overvåget"</string>
     <string name="branded_vpn_footer" msgid="2168111859226496230">"Netværket kan være overvåget"</string>
@@ -501,7 +501,7 @@
     <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Låst op for <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_managed" msgid="8319646760022357585">"<xliff:g id="TRUST_AGENT">%1$s</xliff:g> kører"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
-    <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag underretninger hurtigere"</string>
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag notifikationer hurtigere"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem, før du låser op"</string>
     <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nej tak"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"Konfigurer"</string>
@@ -530,7 +530,7 @@
     <string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
     <string name="stream_music" msgid="9086982948697544342">"Medie"</string>
     <string name="stream_alarm" msgid="5209444229227197703">"Alarm"</string>
-    <string name="stream_notification" msgid="2563720670905665031">"Underretning"</string>
+    <string name="stream_notification" msgid="2563720670905665031">"Notifikation"</string>
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Tonesignalfrekvens (DTMF)"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Hjælpefunktioner"</string>
@@ -549,7 +549,7 @@
     <string name="volume_ringer_hint_unmute" msgid="6602880133293060368">"slå lyden til"</string>
     <string name="volume_ringer_hint_vibrate" msgid="4036802135666515202">"vibrer"</string>
     <string name="volume_dialog_title" msgid="7272969888820035876">"%s lydstyrkeknapper"</string>
-    <string name="volume_dialog_ringer_guidance_ring" msgid="3360373718388509040">"Der afspilles lyd ved opkald og underretninger (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
+    <string name="volume_dialog_ringer_guidance_ring" msgid="3360373718388509040">"Der afspilles lyd ved opkald og notifikationer (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
     <string name="output_title" msgid="5355078100792942802">"Medieafspilning"</string>
     <string name="output_calls_title" msgid="8717692905017206161">"Udgang til telefonopkald"</string>
     <string name="output_none_found" msgid="5544982839808921091">"Der blev ikke fundet nogen enheder"</string>
@@ -595,25 +595,25 @@
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
-    <string name="show_silently" msgid="6841966539811264192">"Vis underretninger lydløst"</string>
-    <string name="block" msgid="2734508760962682611">"Bloker alle underretninger"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Vis notifikationer lydløst"</string>
+    <string name="block" msgid="2734508760962682611">"Bloker alle notifikationer"</string>
     <string name="do_not_silence" msgid="6878060322594892441">"Skal ikke sættes på lydløs"</string>
     <string name="do_not_silence_block" msgid="4070647971382232311">"Skal ikke sættes på lydløs eller blokeres"</string>
-    <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Kontrolelementer til underretning om strøm"</string>
+    <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Kontrolelementer til notifikation om strøm"</string>
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Til"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Fra"</string>
-    <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
-    <string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
-    <string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse underretninger"</string>
-    <string name="notification_channel_minimized" msgid="1664411570378910931">"Disse underretninger minimeres"</string>
-    <string name="notification_channel_silenced" msgid="2877199534497961942">"Disse underretninger vises lydløst"</string>
-    <string name="notification_channel_unsilenced" msgid="4790904571552394137">"Disse underretninger underretter dig"</string>
-    <string name="inline_blocking_helper" msgid="3055064577771478591">"Du afviser som regel disse underretninger. \nVil du blive ved med at se dem?"</string>
-    <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse underretninger?"</string>
-    <string name="inline_stop_button" msgid="4172980096860941033">"Stop underretninger"</string>
+    <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til notifikationer om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps notifikationer. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over notifikationer \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over notifikationer \n\n"<b>"Niveau 0"</b>\n"- Bloker alle notifikationer fra appen."</string>
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifikationer"</string>
+    <string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse notifikationer"</string>
+    <string name="notification_channel_minimized" msgid="1664411570378910931">"Disse notifikationer minimeres"</string>
+    <string name="notification_channel_silenced" msgid="2877199534497961942">"Disse notifikationer vises lydløst"</string>
+    <string name="notification_channel_unsilenced" msgid="4790904571552394137">"Disse notifikationer underretter dig"</string>
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Du afviser som regel disse notifikationer. \nVil du blive ved med at se dem?"</string>
+    <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse notifikationer?"</string>
+    <string name="inline_stop_button" msgid="4172980096860941033">"Stop notifikationer"</string>
     <!-- no translation found for inline_block_button (8735843688021655065) -->
     <skip />
-    <string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise underretninger"</string>
+    <string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise notifikationer"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"Minimer"</string>
     <string name="inline_silent_button_silent" msgid="4411510650503783646">"Vis lydløst"</string>
     <!-- no translation found for inline_silent_button_stay_silent (6308371431217601009) -->
@@ -622,8 +622,8 @@
     <skip />
     <!-- no translation found for inline_silent_button_keep_alerting (327696842264359693) -->
     <skip />
-    <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsætte med at se underretninger fra denne app?"</string>
-    <string name="notification_unblockable_desc" msgid="1037434112919403708">"Disse underretninger kan ikke deaktiveres"</string>
+    <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsætte med at se notifikationer fra denne app?"</string>
+    <string name="notification_unblockable_desc" msgid="1037434112919403708">"Disse notifikationer kan ikke deaktiveres"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"via <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="appops_camera" msgid="8100147441602585776">"Denne app anvender kameraet."</string>
     <string name="appops_microphone" msgid="741508267659494555">"Denne app anvender mikrofonen."</string>
@@ -634,15 +634,15 @@
     <string name="appops_camera_mic_overlay" msgid="6718768197048030993">"Denne app vises over andre apps på din skærm og anvender mikrofonen og kameraet."</string>
     <string name="notification_appops_settings" msgid="1028328314935908050">"Indstillinger"</string>
     <string name="notification_appops_ok" msgid="1156966426011011434">"OK"</string>
-    <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev åbnet"</string>
-    <string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev lukket"</string>
-    <string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillad underretninger fra denne kanal"</string>
+    <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Styring af notifikationer for <xliff:g id="APP_NAME">%1$s</xliff:g> blev åbnet"</string>
+    <string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Styring af notifikationer for <xliff:g id="APP_NAME">%1$s</xliff:g> blev lukket"</string>
+    <string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillad notifikationer fra denne kanal"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
     <string name="notification_app_settings" msgid="420348114670768449">"Tilpas"</string>
     <string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
     <string name="inline_undo" msgid="558916737624706010">"Fortryd"</string>
     <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til underretninger"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til notifikationer"</string>
     <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Indstillinger for udsættelse"</string>
     <string name="notification_menu_snooze_action" msgid="1112254519029621372">"Udsæt"</string>
     <string name="snooze_undo" msgid="6074877317002985129">"FORTRYD"</string>
@@ -689,7 +689,7 @@
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Start"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Seneste"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbage"</string>
-    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Underretninger"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifikationer"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastaturgenveje"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Skift tastaturlayout"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applikationer"</string>
@@ -759,7 +759,7 @@
     <item msgid="2139628951880142927">"Vis procent ved opladning (standard)"</item>
     <item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
   </string-array>
-    <string name="tuner_low_priority" msgid="1325884786608312358">"Vis ikoner for underretninger med lav prioritet"</string>
+    <string name="tuner_low_priority" msgid="1325884786608312358">"Vis ikoner for notifikationer med lav prioritet"</string>
     <string name="other" msgid="4060683095962566764">"Andet"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til opdelt skærm"</string>
     <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"Vis venstre del i fuld skærm"</string>
@@ -779,7 +779,7 @@
     <string name="accessibility_qs_edit_tile_add" msgid="3520406665865985109">"Føj <xliff:g id="TILE_NAME">%1$s</xliff:g> til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_move" msgid="3108103090006972938">"Flyt <xliff:g id="TILE_NAME">%1$s</xliff:g> til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsværktøj for Hurtige indstillinger."</string>
-    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-underretning: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-notifikation: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen fungerer muligvis ikke i opdelt skærm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen understøtter ikke opdelt skærm."</string>
     <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Appen fungerer muligvis ikke på sekundære skærme."</string>
@@ -828,7 +828,7 @@
     <string name="tuner_right" msgid="6222734772467850156">"Højre"</string>
     <string name="tuner_menu" msgid="191640047241552081">"Menu"</string>
     <string name="tuner_app" msgid="3507057938640108777">"Appen <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikationer"</string>
     <string name="notification_channel_battery" msgid="5786118169182888462">"Batteri"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
     <string name="notification_channel_general" msgid="4525309436693914482">"Generelle meddelelser"</string>
@@ -852,7 +852,7 @@
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Behold"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Erstat"</string>
     <string name="running_foreground_services_title" msgid="381024150898615683">"Apps, der kører i baggrunden"</string>
-    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryk for at se info om batteri- og dataforbrug"</string>
     <string name="mobile_data_disable_title" msgid="1068272097382942231">"Vil du deaktivere mobildata?"</string>
     <string name="mobile_data_disable_message" msgid="4756541658791493506">"Du vil ikke have data- eller internetadgang via <xliff:g id="CARRIER">%s</xliff:g>. Der vil kunne være adgang til internettet via Wi-Fi."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"dit mobilselskab"</string>
@@ -876,7 +876,7 @@
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8640691753867990511">"Apps anvender enhedens <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <!-- no translation found for ongoing_privacy_chip_content_multiple_apps_single_op (4871926099254314088) -->
     <string name="ongoing_privacy_dialog_cancel" msgid="5479124524931216790">"Luk"</string>
-    <string name="ongoing_privacy_dialog_open_settings" msgid="2074844974365194279">"Se oplysninger"</string>
+    <string name="ongoing_privacy_dialog_open_settings" msgid="2074844974365194279">"Se info"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Deaktiver sensorer"</string>
     <string name="device_services" msgid="1191212554435440592">"Enhedstjenester"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 447f8b9..0be730a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -894,6 +894,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren aus"</string>
     <string name="device_services" msgid="1191212554435440592">"Gerätedienste"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Kein Titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3891569..31fd04a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 9ef6a83..761acf6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> app más</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Se desactivaron los sensores"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f4e107d..0b3ba5d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desactivados"</string>
     <string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index d8568df..e318291 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Andurid on välja lülitatud"</string>
     <string name="device_services" msgid="1191212554435440592">"Seadme teenused"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Pealkiri puudub"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index cfdf7a5..5b9f0cf 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sentsoreak desaktibatuta daude"</string>
     <string name="device_services" msgid="1191212554435440592">"Gailuetarako zerbitzuak"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ez du izenik"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index cd92d45..931def7 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Anturit pois päältä"</string>
     <string name="device_services" msgid="1191212554435440592">"Laitepalvelut"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ei nimeä"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 695a6a5..d1412aa 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Capteurs désactivés"</string>
     <string name="device_services" msgid="1191212554435440592">"Services de l\'appareil"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sans titre"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a1a0352..8ba575b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Capteurs désactivés"</string>
     <string name="device_services" msgid="1191212554435440592">"Services pour l\'appareil"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sans titre"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 7f111e8..2784567 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Desactivar sensores"</string>
     <string name="device_services" msgid="1191212554435440592">"Servizos do dispositivo"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sen título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 8525094..f17a7f6 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> અન્ય ઍપ</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"સેન્સર બંધ છે"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ડિવાઇસ સેવાઓ"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"કોઈ શીર્ષક નથી"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ae12412..49d923a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Érzékelők kikapcsolva"</string>
     <string name="device_services" msgid="1191212554435440592">"Eszközszolgáltatások"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nincs cím"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index ffcc762..dc592c5 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Տվիչներն անջատած են"</string>
     <string name="device_services" msgid="1191212554435440592">"Սարքի ծառայություններ"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Անանուն"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index eb99a6c..1b43e65 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensor nonaktif"</string>
     <string name="device_services" msgid="1191212554435440592">"Layanan Perangkat"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Tanpa judul"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0040c3c..36b557d 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Slökkt á skynjurum"</string>
     <string name="device_services" msgid="1191212554435440592">"Tækjaþjónusta"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Enginn titill"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 83956e8..21c259a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori disattivati"</string>
     <string name="device_services" msgid="1191212554435440592">"Servizi del dispositivo"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Senza titolo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f7d52ed..ff88a0d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"センサー OFF"</string>
     <string name="device_services" msgid="1191212554435440592">"デバイス サービス"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"タイトルなし"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a1788fc..41ef3e2 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчиктер өшірулі"</string>
     <string name="device_services" msgid="1191212554435440592">"Құрылғы қызметтері"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Атауы жоқ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 0cbd06c..5520cb0 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"បិទឧបករណ៍​ចាប់សញ្ញា"</string>
     <string name="device_services" msgid="1191212554435440592">"សេវាកម្មឧបករណ៍"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"គ្មាន​ចំណងជើង"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 9f46742..f829c12 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> ಇತರ ಆ್ಯಪ್‌ಗಳು</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ಸೆನ್ಸರ್‌ಗಳು ಆಫ್"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ಸಾಧನ ಸೇವೆಗಳು"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 581ffa9..f5168fb 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"센서 사용 안함"</string>
     <string name="device_services" msgid="1191212554435440592">"기기 서비스"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"제목 없음"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ba5a0ac..9558c3a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сенсорлорду өчүрүү"</string>
     <string name="device_services" msgid="1191212554435440592">"Түзмөк кызматтары"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Аталышы жок"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 46cd3f0..5786fb0 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -901,8 +901,6 @@
       <item quantity="other">Dar <xliff:g id="NUM_APPS_1">%d</xliff:g> programų</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Jutikliai išjungti"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Įrenginio paslaugos"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nėra pavadinimo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a1203d5..cebd91c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -896,6 +896,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori izslēgti"</string>
     <string name="device_services" msgid="1191212554435440592">"Ierīces pakalpojumi"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nav nosaukuma"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a3fd2d5..df1bdbb 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите се исклучени"</string>
     <string name="device_services" msgid="1191212554435440592">"Услуги за уредот"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Без наслов"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index f3075b8..5800e0e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"സെൻസറുകൾ ഓഫാണ്"</string>
     <string name="device_services" msgid="1191212554435440592">"ഉപകരണ സേവനങ്ങള്‍"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"പേരില്ല"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 7236893..e96865e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Мэдрэгчийг унтраах"</string>
     <string name="device_services" msgid="1191212554435440592">"Төхөөрөмжийн үйлчилгээ"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Гарчиггүй"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 59e481c..6022a9c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other">इतर <xliff:g id="NUM_APPS_1">%d</xliff:g> अ‍ॅप्स</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"सेन्सर बंद आहेत"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"डिव्हाइस सेवा"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"शीर्षक नाही"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e77771d..1a9eb1c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Penderia dimatikan"</string>
     <string name="device_services" msgid="1191212554435440592">"Perkhidmatan Peranti"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Tiada tajuk"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e5561e8..dbfa01e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string>
     <string name="device_services" msgid="1191212554435440592">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ခေါင်းစဉ် မရှိပါ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a1a12bd..e790684 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorer er av"</string>
     <string name="device_services" msgid="1191212554435440592">"Enhetstjenester"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen tittel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 096db56..9b4441f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> अन्य अनुप्रयोग</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"सेन्सरहरू निष्क्रिय छन्"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"यन्त्रका सेवाहरू"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"शीर्षक छैन"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3607ff8..e570789 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren uit"</string>
     <string name="device_services" msgid="1191212554435440592">"Apparaatservices"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Geen titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 5cb98ee..dd260b1 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g>ଟି ଅନ୍ୟ ଆପ୍‍</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ସେନ୍ସର୍‍ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ଡିଭାଇସ୍‍ ସେବାଗୁଡିକ"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3702e2b..e36fea2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> ਹੋਰ ਐਪਾਂ</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ਸੈਂਸਰ ਬੰਦ ਕਰੋ"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4ece82c..ed2902f 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -901,8 +901,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> inna aplikacja</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Wyłącz czujniki"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Usługi urządzenia"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Bez tytułu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 375f5e8..c1858fc 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> outra aplicação</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 24254f6..c393bde 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -896,6 +896,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori dezactivați"</string>
     <string name="device_services" msgid="1191212554435440592">"Servicii pentru dispozitiv"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Fără titlu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a5d4059..e643c8f 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -902,6 +902,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчики отключены"</string>
     <string name="device_services" msgid="1191212554435440592">"Сервисы устройства"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Без названия"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d9ba8de..bcc444f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -901,8 +901,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> ďalšia aplikácia</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory sú vypnuté"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Služby zariadenia"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5048227..706e700 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -902,6 +902,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Izklop za tipala"</string>
     <string name="device_services" msgid="1191212554435440592">"Storitve naprave"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Brez naslova"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 22ffa81..3c8c3ab 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -800,7 +800,7 @@
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimera"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Stäng"</string>
     <string name="pip_phone_settings" msgid="8080777499521528521">"Inställningar"</string>
-    <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att avvisa"</string>
+    <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att ta bort"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meny"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
     <string name="pip_notification_message" msgid="5619512781514343311">"Om du inte vill att den här funktionen används i <xliff:g id="NAME">%s</xliff:g> öppnar du inställningarna genom att trycka. Sedan inaktiverar du funktionen."</string>
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorer har inaktiverats"</string>
     <string name="device_services" msgid="1191212554435440592">"Enhetstjänster"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a35c78c..f75cc4d 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one">வேறு <xliff:g id="NUM_APPS_0">%d</xliff:g> ஆப்ஸ்</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"சென்சார்களை ஆஃப் செய்தல்"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"சாதன சேவைகள்"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"தலைப்பு இல்லை"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index e7eafbe..894263e 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one">మరో <xliff:g id="NUM_APPS_0">%d</xliff:g> యాప్</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"సెన్సార్‌లు ఆఫ్"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"పరికర సేవలు"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"శీర్షిక లేదు"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 05df7bd..ae581ac 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"เซ็นเซอร์ปิดอยู่"</string>
     <string name="device_services" msgid="1191212554435440592">"บริการของอุปกรณ์"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ไม่มีชื่อ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3bd6ea6..ab20ff0 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Naka-off ang mga sensor"</string>
     <string name="device_services" msgid="1191212554435440592">"Mga Serbisyo ng Device"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Walang pamagat"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4962b16..32201fb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensörler kapalı"</string>
     <string name="device_services" msgid="1191212554435440592">"Cihaz Hizmetleri"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Başlıksız"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3a59029..ee9da5e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"سینسرز آف ہیں"</string>
     <string name="device_services" msgid="1191212554435440592">"آلہ کی سروس"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"کوئی عنوان نہیں ہے"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 3388bcb..488bfae 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar nofaol"</string>
     <string name="device_services" msgid="1191212554435440592">"Qurilma xizmatlari"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nomsiz"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3ebb8dd..125eb72 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Tắt cảm biến"</string>
     <string name="device_services" msgid="1191212554435440592">"Dịch vụ cho thiết bị"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Không có tiêu đề"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d480a8a..d6fd3d89 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"已关闭传感器"</string>
     <string name="device_services" msgid="1191212554435440592">"设备服务"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"无标题"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 7ff70d9..dbe24bb 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"已關閉感應器"</string>
     <string name="device_services" msgid="1191212554435440592">"裝置服務"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7cc5524..476089a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -454,6 +454,10 @@
          RemoteInput.Builder.setEditChoicesBeforeSending. -->
     <bool name="config_smart_replies_in_notifications_edit_choices_before_sending">false</bool>
 
+    <!-- Smart replies in notifications: Whether smart suggestions in notifications are enabled in
+         heads-up notifications.  -->
+    <bool name="config_smart_replies_in_notifications_show_in_heads_up">true</bool>
+
     <!-- Screenshot editing default activity.  Must handle ACTION_EDIT image/png intents.
          Blank sends the user to the Chooser first.
          This name is in the ComponentName flattened format (package/class)  -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 06df0e7..10e5f74 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -997,4 +997,8 @@
     <dimen name="bubble_pointer_width">6dp</dimen>
     <!-- Extra padding around the dismiss target for bubbles -->
     <dimen name="bubble_dismiss_slop">16dp</dimen>
+    <!-- Height of the header within the expanded view. -->
+    <dimen name="bubble_expanded_header_height">48dp</dimen>
+    <!-- Left and right padding applied to the header. -->
+    <dimen name="bubble_expanded_header_horizontal_padding">24dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index dac20b5..633f868 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -102,12 +102,17 @@
     <item type="id" name="action_snooze_assistant_suggestion_1"/>
     <item type="id" name="action_snooze"/>
 
-    <!-- For StatusBarIconContainer to tag its icon views -->
+    <!-- For StatusIconContainer to tag its icon views -->
     <item type="id" name="status_bar_view_state_tag" />
 
     <item type="id" name="display_cutout" />
 
     <!-- Optional cancel button on Keyguard -->
     <item type="id" name="cancel_button"/>
+
+    <!-- AodMaskView transition tag -->
+    <item type="id" name="aod_mask_transition_progress_tag" />
+    <item type="id" name="aod_mask_transition_progress_end_tag" />
+    <item type="id" name="aod_mask_transition_progress_start_tag" />
 </resources>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8a5a69b..22a0b36 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -125,7 +125,7 @@
 
     <style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
         <item name="android:textSize">@dimen/status_bar_clock_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:textColor">@color/status_bar_clock_color</item>
     </style>
 
@@ -265,6 +265,10 @@
         <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
     </style>
 
+    <style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
+        <item name="android:gravity">center</item>
+    </style>
+
     <style name="BaseBrightnessDialogContainer" parent="@style/Theme.SystemUI">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index f3bdbae..078947c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -76,4 +76,10 @@
      */
     float getWindowCornerRadius() = 10;
 
+    /**
+     * If device supports live rounded corners on windows.
+     * This might be turned off for performance reasons
+     */
+    boolean supportsRoundedCornersOnWindows() = 11;
+
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index c0a1d89..e6acfbe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -16,14 +16,10 @@
 
 package com.android.systemui.shared.system;
 
+import android.graphics.HardwareRenderer;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.SyncRtSurfaceTransactionApplier;
-import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
-import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewRootImpl;
 
@@ -31,20 +27,21 @@
 
 /**
  * Helper class to apply surface transactions in sync with RenderThread.
+ *
+ * NOTE: This is a modification of {@link android.view.SyncRtSurfaceTransactionApplier}, we can't 
+ *       currently reference that class from the shared lib as it is hidden.
  */
 public class SyncRtSurfaceTransactionApplierCompat {
 
-    private final SyncRtSurfaceTransactionApplier mApplier;
+    private final Surface mTargetSurface;
+    private final ViewRootImpl mTargetViewRootImpl;
 
     /**
      * @param targetView The view in the surface that acts as synchronization anchor.
      */
     public SyncRtSurfaceTransactionApplierCompat(View targetView) {
-        mApplier = new SyncRtSurfaceTransactionApplier(targetView);
-    }
-
-    private SyncRtSurfaceTransactionApplierCompat(SyncRtSurfaceTransactionApplier applier) {
-        mApplier = applier;
+        mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
+        mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null;
     }
 
     /**
@@ -53,38 +50,74 @@
      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
      *               this method to avoid synchronization issues.
      */
-    public void scheduleApply(final SurfaceParams... params) {
-        mApplier.scheduleApply(convert(params));
-    }
-
-    private SyncRtSurfaceTransactionApplier.SurfaceParams[] convert(SurfaceParams[] params) {
-        SyncRtSurfaceTransactionApplier.SurfaceParams[] result =
-                new SyncRtSurfaceTransactionApplier.SurfaceParams[params.length];
-        for (int i = 0; i < params.length; i++) {
-            result[i] = params[i].mParams;
+    public void scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params) {
+        if (mTargetViewRootImpl == null) {
+            return;
         }
-        return result;
+        mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() {
+            @Override
+            public void onFrameDraw(long frame) {
+                if (mTargetSurface == null || !mTargetSurface.isValid()) {
+                    return;
+                }
+                TransactionCompat t = new TransactionCompat();
+                for (int i = params.length - 1; i >= 0; i--) {
+                    SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
+                            params[i];
+                    SurfaceControlCompat surface = surfaceParams.surface;
+                    t.deferTransactionUntil(surface, mTargetSurface, frame);
+                    applyParams(t, surfaceParams);
+                }
+                t.setEarlyWakeup();
+                t.apply();
+            }
+        });
+
+        // Make sure a frame gets scheduled.
+        mTargetViewRootImpl.getView().invalidate();
     }
 
-    public static void applyParams(TransactionCompat t, SurfaceParams params) {
-        SyncRtSurfaceTransactionApplier.applyParams(t.mTransaction, params.mParams, t.mTmpValues);
+    public static void applyParams(TransactionCompat t,
+            SyncRtSurfaceTransactionApplierCompat.SurfaceParams params) {
+        t.setMatrix(params.surface, params.matrix);
+        t.setWindowCrop(params.surface, params.windowCrop);
+        t.setAlpha(params.surface, params.alpha);
+        t.setLayer(params.surface, params.layer);
+        t.setCornerRadius(params.surface, params.cornerRadius);
+        t.show(params.surface);
     }
 
+    /**
+     * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
+     * attached if necessary.
+     */
     public static void create(final View targetView,
             final Consumer<SyncRtSurfaceTransactionApplierCompat> callback) {
-        SyncRtSurfaceTransactionApplier.create(targetView,
-                new Consumer<SyncRtSurfaceTransactionApplier>() {
-                    @Override
-                    public void accept(SyncRtSurfaceTransactionApplier applier) {
-                        callback.accept(new SyncRtSurfaceTransactionApplierCompat(applier));
-                    }
-                });
+        if (targetView == null) {
+            // No target view, no applier
+            callback.accept(null);
+        } else if (targetView.getViewRootImpl() != null) {
+            // Already attached, we're good to go
+            callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
+        } else {
+            // Haven't been attached before we can get the view root
+            targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View v) {
+                    targetView.removeOnAttachStateChangeListener(this);
+                    callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View v) {
+                    // Do nothing
+                }
+            });
+        }
     }
 
     public static class SurfaceParams {
 
-        private final SyncRtSurfaceTransactionApplier.SurfaceParams mParams;
-
         /**
          * Constructs surface parameters to be applied when the current view state gets pushed to
          * RenderThread.
@@ -96,8 +129,19 @@
          */
         public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
                 Rect windowCrop, int layer, float cornerRadius) {
-            mParams = new SyncRtSurfaceTransactionApplier.SurfaceParams(surface.mSurfaceControl,
-                    alpha, matrix, windowCrop, layer, cornerRadius);
+            this.surface = surface;
+            this.alpha = alpha;
+            this.matrix = new Matrix(matrix);
+            this.windowCrop = new Rect(windowCrop);
+            this.layer = layer;
+            this.cornerRadius = cornerRadius;
         }
+
+        public final SurfaceControlCompat surface;
+        public final float alpha;
+        final float cornerRadius;
+        public final Matrix matrix;
+        public final Rect windowCrop;
+        public final int layer;
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
index 2aba3fa..af32f48 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
@@ -82,6 +82,11 @@
         return this;
     }
 
+    public TransactionCompat setCornerRadius(SurfaceControlCompat surfaceControl, float radius) {
+        mTransaction.setCornerRadius(surfaceControl.mSurfaceControl, radius);
+        return this;
+    }
+
     public TransactionCompat deferTransactionUntil(SurfaceControlCompat surfaceControl,
             IBinder handle, long frameNumber) {
         mTransaction.deferTransactionUntil(surfaceControl.mSurfaceControl, handle, frameNumber);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 27d624a..3cfd6a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -14,13 +14,13 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 
-import java.util.Objects;
 import java.util.TimeZone;
+import java.util.function.Consumer;
 
 /**
  * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
@@ -47,43 +47,19 @@
      * or not to show it below the alternate clock.
      */
     private View mKeyguardStatusArea;
+    /**
+     * Used to select between plugin or default implementations of ClockPlugin interface.
+     */
+    private Extension<ClockPlugin> mClockExtension;
+    /**
+     * Consumer that accepts the a new ClockPlugin implementation when the Extension reloads.
+     */
+    private final Consumer<ClockPlugin> mClockPluginConsumer = plugin -> setClockPlugin(plugin);
+    /**
+     * Maintain state so that a newly connected plugin can be initialized.
+     */
+    private float mDarkAmount;
 
-    private final PluginListener<ClockPlugin> mClockPluginListener =
-            new PluginListener<ClockPlugin>() {
-                @Override
-                public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
-                    disconnectPlugin();
-                    View smallClockView = plugin.getView();
-                    if (smallClockView != null) {
-                        // For now, assume that the most recently connected plugin is the
-                        // selected clock face. In the future, the user should be able to
-                        // pick a clock face from the available plugins.
-                        mSmallClockFrame.addView(smallClockView, -1,
-                                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                        ViewGroup.LayoutParams.WRAP_CONTENT));
-                        initPluginParams();
-                        mClockView.setVisibility(View.GONE);
-                    }
-                    View bigClockView = plugin.getBigClockView();
-                    if (bigClockView != null && mBigClockContainer != null) {
-                        mBigClockContainer.addView(bigClockView);
-                        mBigClockContainer.setVisibility(View.VISIBLE);
-                    }
-                    if (!plugin.shouldShowStatusArea()) {
-                        mKeyguardStatusArea.setVisibility(View.GONE);
-                    }
-                    mClockPlugin = plugin;
-                }
-
-                @Override
-                public void onPluginDisconnected(ClockPlugin plugin) {
-                    if (Objects.equals(plugin, mClockPlugin)) {
-                        disconnectPlugin();
-                        mClockView.setVisibility(View.VISIBLE);
-                        mKeyguardStatusArea.setVisibility(View.VISIBLE);
-                    }
-                }
-            };
     private final StatusBarStateController.StateListener mStateListener =
             new StatusBarStateController.StateListener() {
                 @Override
@@ -111,6 +87,13 @@
         super(context, attrs);
     }
 
+    /**
+     * Returns if this view is presenting a custom clock, or the default implementation.
+     */
+    public boolean hasCustomClock() {
+        return mClockPlugin != null;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -122,18 +105,62 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener,
-                ClockPlugin.class);
+        mClockExtension = Dependency.get(ExtensionController.class).newExtension(ClockPlugin.class)
+                .withPlugin(ClockPlugin.class)
+                .withCallback(mClockPluginConsumer)
+                .build();
         Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener);
+        mClockExtension.destroy();
         Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
     }
 
+    private void setClockPlugin(ClockPlugin plugin) {
+        // Disconnect from existing plugin.
+        if (mClockPlugin != null) {
+            View smallClockView = mClockPlugin.getView();
+            if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) {
+                mSmallClockFrame.removeView(smallClockView);
+            }
+            if (mBigClockContainer != null) {
+                mBigClockContainer.removeAllViews();
+                mBigClockContainer.setVisibility(View.GONE);
+            }
+            mClockPlugin = null;
+        }
+        if (plugin == null) {
+            mClockView.setVisibility(View.VISIBLE);
+            mKeyguardStatusArea.setVisibility(View.VISIBLE);
+            return;
+        }
+        // Attach small and big clock views to hierarchy.
+        View smallClockView = plugin.getView();
+        if (smallClockView != null) {
+            mSmallClockFrame.addView(smallClockView, -1,
+                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT));
+            mClockView.setVisibility(View.GONE);
+        }
+        View bigClockView = plugin.getBigClockView();
+        if (bigClockView != null && mBigClockContainer != null) {
+            mBigClockContainer.addView(bigClockView);
+            mBigClockContainer.setVisibility(View.VISIBLE);
+        }
+        // Hide default clock.
+        if (!plugin.shouldShowStatusArea()) {
+            mKeyguardStatusArea.setVisibility(View.GONE);
+        }
+        // Initialize plugin parameters.
+        mClockPlugin = plugin;
+        mClockPlugin.setStyle(getPaint().getStyle());
+        mClockPlugin.setTextColor(getCurrentTextColor());
+        mClockPlugin.setDarkAmount(mDarkAmount);
+    }
+
     /**
      * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
      */
@@ -193,6 +220,7 @@
      * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
      */
     public void setDarkAmount(float darkAmount) {
+        mDarkAmount = darkAmount;
         if (mClockPlugin != null) {
             mClockPlugin.setDarkAmount(darkAmount);
         }
@@ -232,33 +260,9 @@
         }
     }
 
-    /**
-     * When plugin changes, set all kept parameters into newer plugin.
-     */
-    private void initPluginParams() {
-        if (mClockPlugin != null) {
-            mClockPlugin.setStyle(getPaint().getStyle());
-            mClockPlugin.setTextColor(getCurrentTextColor());
-        }
-    }
-
-    private void disconnectPlugin() {
-        if (mClockPlugin != null) {
-            View smallClockView = mClockPlugin.getView();
-            if (smallClockView != null) {
-                mSmallClockFrame.removeView(smallClockView);
-            }
-            if (mBigClockContainer != null) {
-                mBigClockContainer.removeAllViews();
-                mBigClockContainer.setVisibility(View.GONE);
-            }
-            mClockPlugin = null;
-        }
-    }
-
     @VisibleForTesting (otherwise = VisibleForTesting.NONE)
-    PluginListener getClockPluginListener() {
-        return mClockPluginListener;
+    Consumer<ClockPlugin> getClockPluginConsumer() {
+        return mClockPluginConsumer;
     }
 
     @VisibleForTesting (otherwise = VisibleForTesting.NONE)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index c6f1726..f0cdc89 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -141,6 +141,13 @@
         onDensityOrFontScaleChanged();
     }
 
+    /**
+     * If we're presenting a custom clock of just the default one.
+     */
+    public boolean hasCustomClock() {
+        return mClockView.hasCustomClock();
+    }
+
     private void setEnableMarquee(boolean enabled) {
         if (DEBUG) Log.v(TAG, "Schedule setEnableMarquee: " + (enabled ? "Enable" : "Disable"));
         if (enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 6864ea1..2006794 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -40,7 +40,6 @@
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -56,7 +55,6 @@
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.Utils.DisableStateTracker;
@@ -71,11 +69,12 @@
 
 
     @Retention(SOURCE)
-    @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF})
+    @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
     public @interface BatteryPercentMode {}
     public static final int MODE_DEFAULT = 0;
     public static final int MODE_ON = 1;
     public static final int MODE_OFF = 2;
+    public static final int MODE_ESTIMATE = 3;
 
     private final BatteryMeterDrawableBase mDrawable;
     private final String mSlotBattery;
@@ -93,6 +92,7 @@
     // Some places may need to show the battery conditionally, and not obey the tuner
     private boolean mIgnoreTunerUpdates;
     private boolean mIsSubscribedForTunerUpdates;
+    private boolean mCharging;
 
     private int mDarkModeBackgroundColor;
     private int mDarkModeFillColor;
@@ -276,9 +276,6 @@
     public void onTuningChanged(String key, String newValue) {
         if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
             ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
-            boolean hidden = icons.contains(mSlotBattery);
-            Dependency.get(IconLogger.class).onIconVisibility(mSlotBattery, !hidden);
-            setVisibility(hidden ? View.GONE : View.VISIBLE);
         }
     }
 
@@ -308,6 +305,7 @@
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         mDrawable.setBatteryLevel(level);
         mDrawable.setCharging(pluggedIn);
+        mCharging = pluggedIn;
         mLevel = level;
         updatePercentText();
         setContentDescription(
@@ -337,9 +335,19 @@
     }
 
     private void updatePercentText() {
+        if (mBatteryController == null) {
+            return;
+        }
+
         if (mBatteryPercentView != null) {
-            mBatteryPercentView.setText(
-                    NumberFormat.getPercentInstance().format(mLevel / 100f));
+            if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
+                mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
+                    mBatteryPercentView.setText(estimate);
+                });
+            } else {
+                mBatteryPercentView.setText(
+                        NumberFormat.getPercentInstance().format(mLevel / 100f));
+            }
         }
     }
 
@@ -350,7 +358,7 @@
                 SHOW_BATTERY_PERCENT, 0, mUser);
 
         if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
-                || mShowPercentMode == MODE_ON) {
+                || mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) {
             if (!showing) {
                 mBatteryPercentView = loadPercentView();
                 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 9d81064..ec6ecc6 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -86,7 +86,6 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -217,7 +216,6 @@
     @Inject Lazy<LeakDetector> mLeakDetector;
     @Inject Lazy<LeakReporter> mLeakReporter;
     @Inject Lazy<GarbageMonitor> mGarbageMonitor;
-    @Inject Lazy<IconLogger> mIconLogger;
     @Inject Lazy<TunerService> mTunerService;
     @Inject Lazy<StatusBarWindowController> mStatusBarWindowController;
     @Inject Lazy<DarkIconDispatcher> mDarkIconDispatcher;
@@ -392,8 +390,6 @@
 
         mProviders.put(PowerUI.WarningsUI.class, mWarningsUI::get);
 
-        mProviders.put(IconLogger.class, mIconLogger::get);
-
         mProviders.put(LightBarController.class, mLightBarController::get);
 
         mProviders.put(IWindowManager.class, mIWindowManager::get);
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index f324a05b..ce9c637 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -46,8 +46,6 @@
 import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.IconLogger;
-import com.android.systemui.statusbar.policy.IconLoggerImpl;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -133,11 +131,6 @@
     /**
      */
     @Binds
-    public abstract IconLogger provideIconLogger(IconLoggerImpl loggerImpl);
-
-    /**
-     */
-    @Binds
     public abstract CastController provideCastController(CastControllerImpl controllerImpl);
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index d0111cb..f66a57b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -136,8 +137,8 @@
     }
 
     public NotificationIconAreaController createNotificationIconAreaController(Context context,
-            StatusBar statusBar) {
-        return new NotificationIconAreaController(context, statusBar);
+            StatusBar statusBar, StatusBarStateController statusBarStateController) {
+        return new NotificationIconAreaController(context, statusBar, statusBarStateController);
     }
 
     public KeyguardIndicationController createKeyguardIndicationController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
index 9f363f6..7e5b426 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
@@ -25,12 +25,20 @@
     private int mUid;
     private String mPackageName;
     private long mTimeStarted;
+    private String mState;
 
     public AppOpItem(int code, int uid, String packageName, long timeStarted) {
         this.mCode = code;
         this.mUid = uid;
         this.mPackageName = packageName;
         this.mTimeStarted = timeStarted;
+        mState = new StringBuilder()
+                .append("AppOpItem(")
+                .append("Op code=").append(code).append(", ")
+                .append("UID=").append(uid).append(", ")
+                .append("Package name=").append(packageName)
+                .append(")")
+                .toString();
     }
 
     public int getCode() {
@@ -48,4 +56,9 @@
     public long getTimeStarted() {
         return mTimeStarted;
     }
+
+    @Override
+    public String toString() {
+        return mState;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index e3bcb37..c013df3 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -29,7 +29,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dumpable;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -47,7 +50,7 @@
 @Singleton
 public class AppOpsControllerImpl implements AppOpsController,
         AppOpsManager.OnOpActiveChangedListener,
-        AppOpsManager.OnOpNotedListener {
+        AppOpsManager.OnOpNotedListener, Dumpable {
 
     private static final long NOTED_OP_TIME_DELAY_MS = 5000;
     private static final String TAG = "AppOpsControllerImpl";
@@ -271,6 +274,22 @@
         }
     }
 
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("AppOpsController state:");
+        pw.println("  Active Items:");
+        for (int i = 0; i < mActiveItems.size(); i++) {
+            final AppOpItem item = mActiveItems.get(i);
+            pw.print("    "); pw.println(item.toString());
+        }
+        pw.println("  Noted Items:");
+        for (int i = 0; i < mNotedItems.size(); i++) {
+            final AppOpItem item = mNotedItems.get(i);
+            pw.print("    "); pw.println(item.toString());
+        }
+
+    }
+
     protected final class H extends Handler {
         H(Looper looper) {
             super(looper);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index 3167b9e..016b8fe 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -33,9 +33,6 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.CommandQueue;
 
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * Receives messages sent from AuthenticationClient and shows the appropriate biometric UI (e.g.
  * BiometricDialogView).
@@ -52,10 +49,8 @@
     private static final int MSG_BUTTON_NEGATIVE = 6;
     private static final int MSG_USER_CANCELED = 7;
     private static final int MSG_BUTTON_POSITIVE = 8;
-    private static final int MSG_BIOMETRIC_SHOW_TRY_AGAIN = 9;
-    private static final int MSG_TRY_AGAIN_PRESSED = 10;
+    private static final int MSG_TRY_AGAIN_PRESSED = 9;
 
-    private Map<Integer, BiometricDialogView> mDialogs; // BiometricAuthenticator type, view
     private SomeArgs mCurrentDialogArgs;
     private BiometricDialogView mCurrentDialog;
     private WindowManager mWindowManager;
@@ -63,21 +58,22 @@
     private boolean mDialogShowing;
     private Callback mCallback = new Callback();
 
-    private boolean mTryAgainShowing; // No good place to save state before config change :/
-    private boolean mConfirmShowing; // No good place to save state before config change :/
-
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_SHOW_DIALOG:
-                    handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */);
+                    handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */,
+                            null /* savedState */);
                     break;
                 case MSG_BIOMETRIC_AUTHENTICATED:
-                    handleBiometricAuthenticated();
+                    handleBiometricAuthenticated((boolean) msg.obj);
                     break;
                 case MSG_BIOMETRIC_HELP:
-                    handleBiometricHelp((String) msg.obj);
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleBiometricHelp((String) args.arg1 /* message */,
+                            (boolean) args.arg2 /* requireTryAgain */);
+                    args.recycle();
                     break;
                 case MSG_BIOMETRIC_ERROR:
                     handleBiometricError((String) msg.obj);
@@ -94,9 +90,6 @@
                 case MSG_BUTTON_POSITIVE:
                     handleButtonPositive();
                     break;
-                case MSG_BIOMETRIC_SHOW_TRY_AGAIN:
-                    handleShowTryAgain();
-                    break;
                 case MSG_TRY_AGAIN_PRESSED:
                     handleTryAgainPressed();
                     break;
@@ -137,30 +130,22 @@
 
     @Override
     public void start() {
-        createDialogs();
-
-        if (!mDialogs.isEmpty()) {
+        final PackageManager pm = mContext.getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+                || pm.hasSystemFeature(PackageManager.FEATURE_FACE)
+                || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
             getComponent(CommandQueue.class).addCallback(this);
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         }
     }
 
-    private void createDialogs() {
-        final PackageManager pm = mContext.getPackageManager();
-        mDialogs = new HashMap<>();
-        if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
-            mDialogs.put(BiometricAuthenticator.TYPE_FACE, new FaceDialogView(mContext, mCallback));
-        }
-        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
-            mDialogs.put(BiometricAuthenticator.TYPE_FINGERPRINT,
-                    new FingerprintDialogView(mContext, mCallback));
-        }
-    }
-
     @Override
     public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
             int type, boolean requireConfirmation, int userId) {
-        if (DEBUG) Log.d(TAG, "showBiometricDialog, type: " + type);
+        if (DEBUG) {
+            Log.d(TAG, "showBiometricDialog, type: " + type
+                    + ", requireConfirmation: " + requireConfirmation);
+        }
         // Remove these messages as they are part of the previous client
         mHandler.removeMessages(MSG_BIOMETRIC_ERROR);
         mHandler.removeMessages(MSG_BIOMETRIC_HELP);
@@ -176,15 +161,18 @@
     }
 
     @Override
-    public void onBiometricAuthenticated() {
-        if (DEBUG) Log.d(TAG, "onBiometricAuthenticated");
-        mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget();
+    public void onBiometricAuthenticated(boolean authenticated) {
+        if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated);
+        mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, authenticated).sendToTarget();
     }
 
     @Override
     public void onBiometricHelp(String message) {
         if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
-        mHandler.obtainMessage(MSG_BIOMETRIC_HELP, message).sendToTarget();
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = message;
+        args.arg2 = false; // requireTryAgain
+        mHandler.obtainMessage(MSG_BIOMETRIC_HELP, args).sendToTarget();
     }
 
     @Override
@@ -199,16 +187,21 @@
         mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
     }
 
-    @Override
-    public void showBiometricTryAgain() {
-        if (DEBUG) Log.d(TAG, "showBiometricTryAgain");
-        mHandler.obtainMessage(MSG_BIOMETRIC_SHOW_TRY_AGAIN).sendToTarget();
-    }
-
-    private void handleShowDialog(SomeArgs args, boolean skipAnimation) {
+    private void handleShowDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
         mCurrentDialogArgs = args;
         final int type = args.argi1;
-        mCurrentDialog = mDialogs.get(type);
+
+        if (type == BiometricAuthenticator.TYPE_FINGERPRINT) {
+            mCurrentDialog = new FingerprintDialogView(mContext, mCallback);
+        } else if (type == BiometricAuthenticator.TYPE_FACE) {
+            mCurrentDialog = new FaceDialogView(mContext, mCallback);
+        } else {
+            Log.e(TAG, "Unsupported type: " + type);
+        }
+
+        if (savedState != null) {
+            mCurrentDialog.restoreState(savedState);
+        }
 
         if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
                 + mCurrentDialog.isAnimatingAway() + " type: " + type);
@@ -224,32 +217,36 @@
         mCurrentDialog.setRequireConfirmation((boolean) args.arg3);
         mCurrentDialog.setUserId(args.argi2);
         mCurrentDialog.setSkipIntro(skipAnimation);
-        mCurrentDialog.setPendingTryAgain(mTryAgainShowing);
-        mCurrentDialog.setPendingConfirm(mConfirmShowing);
         mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
         mDialogShowing = true;
     }
 
-    private void handleBiometricAuthenticated() {
-        if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated");
+    private void handleBiometricAuthenticated(boolean authenticated) {
+        if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated: " + authenticated);
 
-        mCurrentDialog.announceForAccessibility(
-                mContext.getResources()
-                        .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
-        if (mCurrentDialog.requiresConfirmation()) {
-            mConfirmShowing = true;
-            mCurrentDialog.showConfirmationButton(true /* show */);
+        if (authenticated) {
+            mCurrentDialog.announceForAccessibility(
+                    mContext.getResources()
+                            .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
+            if (mCurrentDialog.requiresConfirmation()) {
+                mCurrentDialog.showConfirmationButton(true /* show */);
+            } else {
+                mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
+                mHandler.postDelayed(() -> {
+                    handleHideDialog(false /* userCanceled */);
+                }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs());
+            }
         } else {
-            mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
-            mHandler.postDelayed(() -> {
-                handleHideDialog(false /* userCanceled */);
-            }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs());
+            handleBiometricHelp(mContext.getResources()
+                    .getString(com.android.internal.R.string.biometric_not_recognized),
+                    true /* requireTryAgain */);
+            mCurrentDialog.showTryAgainButton(true /* show */);
         }
     }
 
-    private void handleBiometricHelp(String message) {
+    private void handleBiometricHelp(String message, boolean requireTryAgain) {
         if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message);
-        mCurrentDialog.showHelpMessage(message);
+        mCurrentDialog.showHelpMessage(message, requireTryAgain);
     }
 
     private void handleBiometricError(String error) {
@@ -258,7 +255,6 @@
             if (DEBUG) Log.d(TAG, "Dialog already dismissed");
             return;
         }
-        mTryAgainShowing = false;
         mCurrentDialog.showErrorMessage(error);
     }
 
@@ -279,8 +275,6 @@
         }
         mReceiver = null;
         mDialogShowing = false;
-        mConfirmShowing = false;
-        mTryAgainShowing = false;
         mCurrentDialog.startDismiss();
     }
 
@@ -294,7 +288,6 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception when handling negative button", e);
         }
-        mTryAgainShowing = false;
         handleHideDialog(false /* userCanceled */);
     }
 
@@ -308,25 +301,16 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception when handling positive button", e);
         }
-        mConfirmShowing = false;
         handleHideDialog(false /* userCanceled */);
     }
 
     private void handleUserCanceled() {
-        mTryAgainShowing = false;
-        mConfirmShowing = false;
         handleHideDialog(true /* userCanceled */);
     }
 
-    private void handleShowTryAgain() {
-        mCurrentDialog.showTryAgainButton(true /* show */);
-        mTryAgainShowing = true;
-    }
-
     private void handleTryAgainPressed() {
         try {
             mCurrentDialog.clearTemporaryMessage();
-            mTryAgainShowing = false;
             mReceiver.onTryAgainPressed();
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException when handling try again", e);
@@ -337,13 +321,20 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         final boolean wasShowing = mDialogShowing;
+
+        // Save the state of the current dialog (buttons showing, etc)
+        final Bundle savedState = new Bundle();
+        if (mCurrentDialog != null) {
+            mCurrentDialog.onSaveState(savedState);
+        }
+
         if (mDialogShowing) {
             mCurrentDialog.forceRemove();
             mDialogShowing = false;
         }
-        createDialogs();
+
         if (wasShowing) {
-            handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */);
+            handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index 9934bfd..c927677 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -56,12 +56,15 @@
 
     private static final String TAG = "BiometricDialogView";
 
+    private static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility";
+    private static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility";
+
     private static final int ANIMATION_DURATION_SHOW = 250; // ms
     private static final int ANIMATION_DURATION_AWAY = 350; // ms
 
     private static final int MSG_CLEAR_MESSAGE = 1;
 
-    protected static final int STATE_NONE = 0;
+    protected static final int STATE_IDLE = 0;
     protected static final int STATE_AUTHENTICATING = 1;
     protected static final int STATE_ERROR = 2;
     protected static final int STATE_PENDING_CONFIRMATION = 3;
@@ -74,16 +77,24 @@
     private final DevicePolicyManager mDevicePolicyManager;
     private final float mAnimationTranslationOffset;
     private final int mErrorColor;
-    private final int mTextColor;
     private final float mDialogWidth;
     private final DialogViewCallback mCallback;
 
-    private ViewGroup mLayout;
-    private final Button mPositiveButton;
-    private final Button mNegativeButton;
-    private final TextView mErrorText;
+    protected final ViewGroup mLayout;
+    protected final LinearLayout mDialog;
+    protected final TextView mTitleText;
+    protected final TextView mSubtitleText;
+    protected final TextView mDescriptionText;
+    protected final ImageView mBiometricIcon;
+    protected final TextView mErrorText;
+    protected final Button mPositiveButton;
+    protected final Button mNegativeButton;
+    protected final Button mTryAgainButton;
+
+    protected final int mTextColor;
+
     private Bundle mBundle;
-    private final LinearLayout mDialog;
+
     private int mLastState;
     private boolean mAnimatingAway;
     private boolean mWasForceRemoved;
@@ -91,15 +102,14 @@
     protected boolean mRequireConfirmation;
     private int mUserId; // used to determine if we should show work background
 
-    private boolean mPendingShowTryAgain;
-    private boolean mPendingShowConfirm;
-
     protected abstract int getHintStringResourceId();
     protected abstract int getAuthenticatedAccessibilityResourceId();
     protected abstract int getIconDescriptionResourceId();
     protected abstract Drawable getAnimationForTransition(int oldState, int newState);
     protected abstract boolean shouldAnimateForTransition(int oldState, int newState);
     protected abstract int getDelayAfterAuthenticatedDurationMs();
+    protected abstract boolean shouldGrayAreaDismissDialog();
+    protected abstract void handleClearMessage(boolean requireTryAgain);
 
     private final Runnable mShowAnimationRunnable = new Runnable() {
         @Override
@@ -124,7 +134,7 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_CLEAR_MESSAGE:
-                    handleClearMessage();
+                    handleClearMessage((boolean) msg.obj /* requireTryAgain */);
                     break;
                 default:
                     Log.e(TAG, "Unhandled message: " + msg.what);
@@ -158,10 +168,6 @@
         mLayout = (ViewGroup) factory.inflate(R.layout.biometric_dialog, this, false);
         addView(mLayout);
 
-        mDialog = mLayout.findViewById(R.id.dialog);
-
-        mErrorText = mLayout.findViewById(R.id.error);
-
         mLayout.setOnKeyListener(new View.OnKeyListener() {
             boolean downPressed = false;
             @Override
@@ -184,12 +190,19 @@
         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 ImageView icon = mLayout.findViewById(R.id.biometric_icon);
-        final Button tryAgain = mLayout.findViewById(R.id.button_try_again);
+
+        mDialog = mLayout.findViewById(R.id.dialog);
+        mTitleText = mLayout.findViewById(R.id.title);
+        mSubtitleText = mLayout.findViewById(R.id.subtitle);
+        mDescriptionText = mLayout.findViewById(R.id.description);
+        mBiometricIcon = mLayout.findViewById(R.id.biometric_icon);
+        mErrorText = mLayout.findViewById(R.id.error);
         mNegativeButton = mLayout.findViewById(R.id.button2);
         mPositiveButton = mLayout.findViewById(R.id.button1);
+        mTryAgainButton = mLayout.findViewById(R.id.button_try_again);
 
-        icon.setContentDescription(getResources().getString(getIconDescriptionResourceId()));
+        mBiometricIcon.setContentDescription(
+                getResources().getString(getIconDescriptionResourceId()));
 
         setDismissesDialog(space);
         setDismissesDialog(leftSpace);
@@ -206,8 +219,9 @@
             }, getDelayAfterAuthenticatedDurationMs());
         });
 
-        tryAgain.setOnClickListener((View v) -> {
+        mTryAgainButton.setOnClickListener((View v) -> {
             showTryAgainButton(false /* show */);
+            handleClearMessage(false /* requireTryAgain */);
             mCallback.onTryAgainPressed();
         });
 
@@ -215,15 +229,17 @@
         mLayout.requestFocus();
     }
 
+    public void onSaveState(Bundle bundle) {
+        bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility());
+        bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility());
+    }
+
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         mErrorText.setText(getHintStringResourceId());
 
-        final TextView title = mLayout.findViewById(R.id.title);
-        final TextView subtitle = mLayout.findViewById(R.id.subtitle);
-        final TextView description = mLayout.findViewById(R.id.description);
         final ImageView backgroundView = mLayout.findViewById(R.id.background);
 
         if (mUserManager.isManagedProfile(mUserId)) {
@@ -244,36 +260,34 @@
             mDialog.getLayoutParams().width = (int) mDialogWidth;
         }
 
-        mLastState = STATE_NONE;
+        mLastState = STATE_IDLE;
         updateState(STATE_AUTHENTICATING);
 
         CharSequence titleText = mBundle.getCharSequence(BiometricPrompt.KEY_TITLE);
 
-        title.setText(titleText);
-        title.setSelected(true);
+        mTitleText.setVisibility(View.VISIBLE);
+        mTitleText.setText(titleText);
+        mTitleText.setSelected(true);
 
         final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
         if (TextUtils.isEmpty(subtitleText)) {
-            subtitle.setVisibility(View.GONE);
+            mSubtitleText.setVisibility(View.GONE);
         } else {
-            subtitle.setVisibility(View.VISIBLE);
-            subtitle.setText(subtitleText);
+            mSubtitleText.setVisibility(View.VISIBLE);
+            mSubtitleText.setText(subtitleText);
         }
 
         final CharSequence descriptionText =
                 mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
         if (TextUtils.isEmpty(descriptionText)) {
-            description.setVisibility(View.GONE);
+            mDescriptionText.setVisibility(View.GONE);
         } else {
-            description.setVisibility(View.VISIBLE);
-            description.setText(descriptionText);
+            mDescriptionText.setVisibility(View.VISIBLE);
+            mDescriptionText.setText(descriptionText);
         }
 
         mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
 
-        showTryAgainButton(mPendingShowTryAgain);
-        showConfirmationButton(mPendingShowConfirm);
-
         if (mWasForceRemoved || mSkipIntro) {
             // Show the dialog immediately
             mLayout.animate().cancel();
@@ -302,8 +316,7 @@
                 ? (AnimatedVectorDrawable) icon
                 : null;
 
-        final ImageView imageView = getLayout().findViewById(R.id.biometric_icon);
-        imageView.setImageDrawable(icon);
+        mBiometricIcon.setImageDrawable(icon);
 
         if (animation != null && shouldAnimateForTransition(lastState, newState)) {
             animation.forceAnimationOnUI();
@@ -314,7 +327,7 @@
     private void setDismissesDialog(View v) {
         v.setClickable(true);
         v.setOnTouchListener((View view, MotionEvent event) -> {
-            if (mLastState != STATE_AUTHENTICATED) {
+            if (mLastState != STATE_AUTHENTICATED && shouldGrayAreaDismissDialog()) {
                 mCallback.onUserCanceled();
             }
             return true;
@@ -331,11 +344,9 @@
                 mWindowManager.removeView(BiometricDialogView.this);
                 mAnimatingAway = false;
                 // Set the icons / text back to normal state
-                handleClearMessage();
+                handleClearMessage(false /* requireTryAgain */);
                 showTryAgainButton(false /* show */);
-                mPendingShowTryAgain = false;
-                mPendingShowConfirm = false;
-                updateState(STATE_NONE);
+                updateState(STATE_IDLE);
             }
         };
 
@@ -412,35 +423,28 @@
         return mLayout;
     }
 
-    // Clears the temporary message and shows the help message.
-    private void handleClearMessage() {
-        updateState(STATE_AUTHENTICATING);
-        mErrorText.setText(getHintStringResourceId());
-        mErrorText.setTextColor(mTextColor);
-    }
-
     // Shows an error/help message
-    private void showTemporaryMessage(String message) {
+    private void showTemporaryMessage(String message, boolean requireTryAgain) {
         mHandler.removeMessages(MSG_CLEAR_MESSAGE);
         updateState(STATE_ERROR);
         mErrorText.setText(message);
         mErrorText.setTextColor(mErrorColor);
         mErrorText.setContentDescription(message);
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE),
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE, requireTryAgain),
                 BiometricPrompt.HIDE_DIALOG_DELAY);
     }
 
     public void clearTemporaryMessage() {
         mHandler.removeMessages(MSG_CLEAR_MESSAGE);
-        mHandler.obtainMessage(MSG_CLEAR_MESSAGE).sendToTarget();
+        mHandler.obtainMessage(MSG_CLEAR_MESSAGE, false /* requireTryAgain */).sendToTarget();
     }
 
-    public void showHelpMessage(String message) {
-        showTemporaryMessage(message);
+    public void showHelpMessage(String message, boolean requireTryAgain) {
+        showTemporaryMessage(message, requireTryAgain);
     }
 
     public void showErrorMessage(String error) {
-        showTemporaryMessage(error);
+        showTemporaryMessage(error, false /* requireTryAgain */);
         showTryAgainButton(false /* show */);
         mCallback.onErrorShown();
     }
@@ -459,22 +463,11 @@
     }
 
     public void showTryAgainButton(boolean show) {
-        final Button tryAgain = mLayout.findViewById(R.id.button_try_again);
-        if (show) {
-            tryAgain.setVisibility(View.VISIBLE);
-        } else {
-            tryAgain.setVisibility(View.GONE);
-        }
     }
 
-    // Set the state before the window is attached, so we know if the dialog should be started
-    // with or without the button. This is because there's no good onPause signal
-    public void setPendingTryAgain(boolean show) {
-        mPendingShowTryAgain = show;
-    }
-
-    public void setPendingConfirm(boolean show) {
-        mPendingShowConfirm = show;
+    public void restoreState(Bundle bundle) {
+        mTryAgainButton.setVisibility(bundle.getInt(KEY_TRY_AGAIN_VISIBILITY));
+        mPositiveButton.setVisibility(bundle.getInt(KEY_CONFIRM_VISIBILITY));
     }
 
     public WindowManager.LayoutParams getLayoutParams() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index de3f947..9fba44b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -16,8 +16,18 @@
 
 package com.android.systemui.biometrics;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.graphics.Outline;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewOutlineProvider;
 
 import com.android.systemui.R;
 
@@ -28,13 +38,263 @@
  */
 public class FaceDialogView extends BiometricDialogView {
 
+    private static final String TAG = "FaceDialogView";
+    private static final String KEY_DIALOG_SIZE = "key_dialog_size";
+
     private static final int HIDE_DIALOG_DELAY = 500; // ms
+    private static final int IMPLICIT_Y_PADDING = 16; // dp
+    private static final int GROW_DURATION = 150; // ms
+    private static final int TEXT_ANIMATE_DISTANCE = 32; // dp
+
+    private static final int SIZE_UNKNOWN = 0;
+    private static final int SIZE_SMALL = 1;
+    private static final int SIZE_GROWING = 2;
+    private static final int SIZE_BIG = 3;
+
+    private int mSize;
+    private float mIconOriginalY;
+    private DialogOutlineProvider mOutlineProvider = new DialogOutlineProvider();
+
+    private final class DialogOutlineProvider extends ViewOutlineProvider {
+
+        float mY;
+
+        @Override
+        public void getOutline(View view, Outline outline) {
+            outline.setRoundRect(
+                    0 /* left */,
+                    (int) mY, /* top */
+                    mDialog.getWidth() /* right */,
+                    mDialog.getBottom(), /* bottom */
+                    getResources().getDimension(R.dimen.biometric_dialog_corner_size));
+        }
+
+        int calculateSmall() {
+            final float padding = dpToPixels(IMPLICIT_Y_PADDING);
+            return mDialog.getHeight() - mBiometricIcon.getHeight() - 2 * (int) padding;
+        }
+
+        void setOutlineY(float y) {
+            mY = y;
+        }
+    }
 
     public FaceDialogView(Context context,
             DialogViewCallback callback) {
         super(context, callback);
     }
 
+    private void updateSize(int newSize) {
+        final float padding = dpToPixels(IMPLICIT_Y_PADDING);
+        final float iconSmallPositionY = mDialog.getHeight() - mBiometricIcon.getHeight() - padding;
+
+        if (newSize == SIZE_SMALL) {
+            // These fields are required and/or always hold a spot on the UI, so should be set to
+            // INVISIBLE so they keep their position
+            mTitleText.setVisibility(View.INVISIBLE);
+            mErrorText.setVisibility(View.INVISIBLE);
+            mNegativeButton.setVisibility(View.INVISIBLE);
+
+            // These fields are optional, so set them to gone or invisible depending on their
+            // usage. If they're empty, they're already set to GONE in BiometricDialogView.
+            if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                mSubtitleText.setVisibility(View.INVISIBLE);
+            }
+            if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                mDescriptionText.setVisibility(View.INVISIBLE);
+            }
+
+            // Move the biometric icon to the small spot
+            mBiometricIcon.setY(iconSmallPositionY);
+
+            // Clip the dialog to the small size
+            mDialog.setOutlineProvider(mOutlineProvider);
+            mOutlineProvider.setOutlineY(mOutlineProvider.calculateSmall());
+
+            mDialog.setClipToOutline(true);
+            mDialog.invalidateOutline();
+
+            mSize = newSize;
+        } else if (mSize == SIZE_SMALL && newSize == SIZE_BIG) {
+            mSize = SIZE_GROWING;
+
+            // Animate the outline
+            final ValueAnimator outlineAnimator =
+                    ValueAnimator.ofFloat(mOutlineProvider.calculateSmall(), 0);
+            outlineAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mOutlineProvider.setOutlineY(y);
+                mDialog.invalidateOutline();
+            });
+
+            // Animate the icon back to original big position
+            final ValueAnimator iconAnimator =
+                    ValueAnimator.ofFloat(iconSmallPositionY, mIconOriginalY);
+            iconAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mBiometricIcon.setY(y);
+            });
+
+            // Animate the error text so it slides up with the icon
+            final ValueAnimator textSlideAnimator =
+                    ValueAnimator.ofFloat(dpToPixels(TEXT_ANIMATE_DISTANCE), 0);
+            textSlideAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mErrorText.setTranslationY(y);
+            });
+
+            // Opacity animator for things that should fade in (title, subtitle, details, negative
+            // button)
+            final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(0, 1);
+            opacityAnimator.addUpdateListener((animation) -> {
+                final float opacity = (float) animation.getAnimatedValue();
+
+                // These fields are required and/or always hold a spot on the UI
+                mTitleText.setAlpha(opacity);
+                mErrorText.setAlpha(opacity);
+                mNegativeButton.setAlpha(opacity);
+                mTryAgainButton.setAlpha(opacity);
+
+                // These fields are optional, so only animate them if they're supposed to be showing
+                if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                    mSubtitleText.setAlpha(opacity);
+                }
+                if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                    mDescriptionText.setAlpha(opacity);
+                }
+            });
+
+            // Choreograph together
+            final AnimatorSet as = new AnimatorSet();
+            as.setDuration(GROW_DURATION);
+            as.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    super.onAnimationStart(animation);
+                    // Set the visibility of opacity-animating views back to VISIBLE
+                    mTitleText.setVisibility(View.VISIBLE);
+                    mErrorText.setVisibility(View.VISIBLE);
+                    mNegativeButton.setVisibility(View.VISIBLE);
+                    mTryAgainButton.setVisibility(View.VISIBLE);
+
+                    if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                        mSubtitleText.setVisibility(View.VISIBLE);
+                    }
+                    if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                        mDescriptionText.setVisibility(View.VISIBLE);
+                    }
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    mSize = SIZE_BIG;
+                }
+            });
+            as.play(outlineAnimator).with(iconAnimator).with(opacityAnimator)
+                    .with(textSlideAnimator);
+            as.start();
+        } else if (mSize == SIZE_BIG) {
+            mDialog.setClipToOutline(false);
+            mDialog.invalidateOutline();
+
+            mBiometricIcon.setY(mIconOriginalY);
+
+            mSize = newSize;
+        }
+    }
+
+    @Override
+    public void onSaveState(Bundle bundle) {
+        super.onSaveState(bundle);
+        bundle.putInt(KEY_DIALOG_SIZE, mSize);
+    }
+
+
+    @Override
+    protected void handleClearMessage(boolean requireTryAgain) {
+        // Clears the temporary message and shows the help message. If requireTryAgain is true,
+        // we will start the authenticating state again.
+        if (!requireTryAgain) {
+            updateState(STATE_AUTHENTICATING);
+            mErrorText.setText(getHintStringResourceId());
+            mErrorText.setTextColor(mTextColor);
+            mErrorText.setVisibility(View.VISIBLE);
+        } else {
+            updateState(STATE_IDLE);
+            mErrorText.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    @Override
+    public void restoreState(Bundle bundle) {
+        super.restoreState(bundle);
+        // Keep in mind that this happens before onAttachedToWindow()
+        mSize = bundle.getInt(KEY_DIALOG_SIZE);
+    }
+
+    /**
+     * Do small/big layout here instead of onAttachedToWindow, since:
+     * 1) We need the big layout to be measured, etc for small -> big animation
+     * 2) We need the dialog measurements to know where to move the biometric icon to
+     *
+     * BiometricDialogView already sets the views to their default big state, so here we only
+     * need to hide the ones that are unnecessary.
+     */
+    @Override
+    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mIconOriginalY == 0) {
+            mIconOriginalY = mBiometricIcon.getY();
+        }
+
+        // UNKNOWN means size hasn't been set yet. First time we create the dialog.
+        // onLayout can happen when visibility of views change (during animation, etc).
+        if (mSize != SIZE_UNKNOWN) {
+            // Probably not the cleanest way to do this, but since dialog is big by default,
+            // and small dialogs can persist across orientation changes, we need to set it to
+            // small size here again.
+            if (mSize == SIZE_SMALL) {
+                updateSize(SIZE_SMALL);
+            }
+            return;
+        }
+
+        // If we don't require confirmation, show the small dialog first (until errors occur).
+        if (!requiresConfirmation()) {
+            updateSize(SIZE_SMALL);
+        } else {
+            updateSize(SIZE_BIG);
+        }
+    }
+
+    @Override
+    public void showErrorMessage(String error) {
+        super.showErrorMessage(error);
+
+        // All error messages will cause the dialog to go from small -> big. Error messages
+        // are messages such as lockout, auth failed, etc.
+        if (mSize == SIZE_SMALL) {
+            updateSize(SIZE_BIG);
+        }
+    }
+
+    @Override
+    public void showTryAgainButton(boolean show) {
+        if (show && mSize == SIZE_SMALL) {
+            // Do not call super, we will nicely animate the alpha together with the rest
+            // of the elements in here.
+            updateSize(SIZE_BIG);
+        } else {
+            if (show) {
+                mTryAgainButton.setVisibility(View.VISIBLE);
+            } else {
+                mTryAgainButton.setVisibility(View.GONE);
+            }
+        }
+    }
+
     @Override
     protected int getHintStringResourceId() {
         return R.string.face_dialog_looking_for_face;
@@ -56,7 +316,9 @@
 
     @Override
     protected boolean shouldAnimateForTransition(int oldState, int newState) {
-        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+        if (oldState == STATE_ERROR && newState == STATE_IDLE) {
+            return true;
+        } else if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
             return false;
         } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             return true;
@@ -78,9 +340,19 @@
     }
 
     @Override
+    protected boolean shouldGrayAreaDismissDialog() {
+        if (mSize == SIZE_SMALL) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
     protected Drawable getAnimationForTransition(int oldState, int newState) {
         int iconRes;
-        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+        if (oldState == STATE_ERROR && newState == STATE_IDLE) {
+            iconRes = R.drawable.face_dialog_error_to_face;
+        } else if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
             iconRes = R.drawable.face_dialog_face_to_error;
         } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             iconRes = R.drawable.face_dialog_face_to_error;
@@ -97,4 +369,14 @@
         }
         return mContext.getDrawable(iconRes);
     }
+
+    private float dpToPixels(float dp) {
+        return dp * ((float) mContext.getResources().getDisplayMetrics().densityDpi
+                / DisplayMetrics.DENSITY_DEFAULT);
+    }
+
+    private float pixelsToDp(float pixels) {
+        return pixels / ((float) mContext.getResources().getDisplayMetrics().densityDpi
+                / DisplayMetrics.DENSITY_DEFAULT);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
index 1a6cee2..c9b30ba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
@@ -32,6 +32,14 @@
             DialogViewCallback callback) {
         super(context, callback);
     }
+
+    @Override
+    protected void handleClearMessage(boolean requireTryAgain) {
+        updateState(STATE_AUTHENTICATING);
+        mErrorText.setText(getHintStringResourceId());
+        mErrorText.setTextColor(mTextColor);
+    }
+
     @Override
     protected int getHintStringResourceId() {
         return R.string.fingerprint_dialog_touch_sensor;
@@ -49,7 +57,7 @@
 
     @Override
     protected boolean shouldAnimateForTransition(int oldState, int newState) {
-        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+        if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
             return false;
         } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             return true;
@@ -68,9 +76,15 @@
     }
 
     @Override
+    protected boolean shouldGrayAreaDismissDialog() {
+        // Fingerprint dialog always dismisses when region outside the dialog is tapped
+        return true;
+    }
+
+    @Override
     protected Drawable getAnimationForTransition(int oldState, int newState) {
         int iconRes;
-        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+        if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
             iconRes = R.drawable.fingerprint_dialog_fp_to_error;
         } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             iconRes = R.drawable.fingerprint_dialog_fp_to_error;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 7577609..9f3ff78 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -23,15 +23,20 @@
 import static com.android.systemui.bubbles.BubbleMovementHelper.EDGE_OVERLAP;
 
 import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
+import android.util.Log;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -68,6 +73,8 @@
     private static final String ENABLE_AUTO_BUBBLE_MESSAGES = "experiment_autobubble_messaging";
     private static final String ENABLE_AUTO_BUBBLE_ONGOING = "experiment_autobubble_ongoing";
     private static final String ENABLE_AUTO_BUBBLE_ALL = "experiment_autobubble_all";
+    private static final String ENABLE_BUBBLE_ACTIVITY_VIEW = "experiment_bubble_activity_view";
+    private static final String ENABLE_BUBBLE_CONTENT_INTENT = "experiment_bubble_content_intent";
 
     private final Context mContext;
     private final NotificationEntryManager mNotificationEntryManager;
@@ -189,6 +196,9 @@
             // It's new
             BubbleView bubble = new BubbleView(mContext);
             bubble.setNotif(notif);
+            if (shouldUseActivityView(mContext)) {
+                bubble.setAppOverlayIntent(getAppOverlayIntent(notif));
+            }
             mBubbles.put(bubble.getKey(), bubble);
 
             boolean setPosition = mStackView != null && mStackView.getVisibility() != VISIBLE;
@@ -216,6 +226,21 @@
         }
     }
 
+    @Nullable
+    private PendingIntent getAppOverlayIntent(NotificationEntry notif) {
+        Notification notification = notif.notification.getNotification();
+        if (canLaunchInActivityView(notification.getAppOverlayIntent())) {
+            return notification.getAppOverlayIntent();
+        } else if (shouldUseContentIntent(mContext)
+                && canLaunchInActivityView(notification.contentIntent)) {
+            Log.d(TAG, "[addBubble " + notif.key
+                    + "]: No appOverlayIntent, using contentIntent.");
+            return notification.contentIntent;
+        }
+        Log.d(TAG, "[addBubble " + notif.key + "]: No supported intent for ActivityView.");
+        return null;
+    }
+
     /**
      * Removes the bubble associated with the {@param uri}.
      */
@@ -223,6 +248,7 @@
         BubbleView bv = mBubbles.get(key);
         if (mStackView != null && bv != null) {
             mStackView.removeBubble(bv);
+            bv.destroyActivityView(mStackView);
             bv.getEntry().setBubbleDismissed(true);
         }
 
@@ -282,9 +308,10 @@
                 }
             }
         }
-        for (BubbleView view : viewsToRemove) {
-            mBubbles.remove(view.getKey());
-            mStackView.removeBubble(view);
+        for (BubbleView bubbleView : viewsToRemove) {
+            mBubbles.remove(bubbleView.getKey());
+            mStackView.removeBubble(bubbleView);
+            bubbleView.destroyActivityView(mStackView);
         }
         if (mStackView != null) {
             mStackView.setVisibility(visible ? VISIBLE : INVISIBLE);
@@ -306,6 +333,17 @@
         return mTempRect;
     }
 
+    private boolean canLaunchInActivityView(PendingIntent intent) {
+        if (intent == null) {
+            return false;
+        }
+        ActivityInfo info =
+                intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
+        return info != null
+                && ActivityInfo.isResizeableMode(info.resizeMode)
+                && (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
+    }
+
     @VisibleForTesting
     BubbleStackView getStackView() {
         return mStackView;
@@ -378,4 +416,14 @@
         return Settings.Secure.getInt(context.getContentResolver(),
                 ENABLE_AUTO_BUBBLE_ALL, 0) != 0;
     }
+
+    private static boolean shouldUseActivityView(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ENABLE_BUBBLE_ACTIVITY_VIEW, 0) != 0;
+    }
+
+    private static boolean shouldUseContentIntent(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ENABLE_BUBBLE_CONTENT_INTENT, 0) != 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
index e28d96b..badefe1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
@@ -24,6 +24,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.TriangleShape;
@@ -35,6 +36,8 @@
 
     // The triangle pointing to the expanded view
     private View mPointerView;
+    // The view displayed between the pointer and the expanded view
+    private TextView mHeaderView;
     // The view that is being displayed for the expanded state
     private View mExpandedView;
 
@@ -68,6 +71,7 @@
                 TriangleShape.create(width, height, true /* pointUp */));
         triangleDrawable.setTint(Color.WHITE); // TODO: dark mode
         mPointerView.setBackground(triangleDrawable);
+        mHeaderView = findViewById(R.id.bubble_content_header);
     }
 
     /**
@@ -80,9 +84,19 @@
     }
 
     /**
+     * Set the text displayed within the header.
+     */
+    public void setHeaderText(CharSequence text) {
+        mHeaderView.setText(text);
+    }
+
+    /**
      * Set the view to display for the expanded state. Passing null will clear the view.
      */
     public void setExpandedView(View view) {
+        if (mExpandedView == view) {
+            return;
+        }
         if (mExpandedView != null) {
             removeView(mExpandedView);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index d69e7b3..3280a33 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -21,10 +21,13 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.app.ActivityView;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.RectF;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -50,6 +53,7 @@
  */
 public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.FloatingView {
 
+    private static final String TAG = "BubbleStackView";
     private Point mDisplaySize;
 
     private FrameLayout mBubbleContainer;
@@ -59,6 +63,7 @@
     private int mBubblePadding;
 
     private boolean mIsExpanded;
+    private int mExpandedBubbleHeight;
     private BubbleView mExpandedBubble;
     private Point mCollapsedPosition;
     private BubbleTouchHandler mTouchHandler;
@@ -106,6 +111,7 @@
         mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
         mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding);
 
+        mExpandedBubbleHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
         mDisplaySize = new Point();
         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         wm.getDefaultDisplay().getSize(mDisplaySize);
@@ -389,27 +395,63 @@
     }
 
     private void updateExpandedBubble() {
-        if (mExpandedBubble != null) {
+        if (mExpandedBubble == null) {
+            return;
+        }
+
+        if (mExpandedBubble.hasAppOverlayIntent()) {
+            ActivityView expandedView = mExpandedBubble.getActivityView();
+            expandedView.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, mExpandedBubbleHeight));
+
+            final PendingIntent intent = mExpandedBubble.getAppOverlayIntent();
+            mExpandedViewContainer.setHeaderText(intent.getIntent().getComponent().toShortString());
+            mExpandedViewContainer.setExpandedView(expandedView);
+            expandedView.setCallback(new ActivityView.StateCallback() {
+                @Override
+                public void onActivityViewReady(ActivityView view) {
+                    Log.d(TAG, "onActivityViewReady("
+                            + mExpandedBubble.getEntry().key + "): " + view);
+                    view.startActivity(intent);
+                }
+
+                @Override
+                public void onActivityViewDestroyed(ActivityView view) {
+                    NotificationEntry entry = mExpandedBubble.getEntry();
+                    Log.d(TAG, "onActivityViewDestroyed(key="
+                            + ((entry != null) ? entry.key : "(none)") + "): " + view);
+                }
+            });
+        } else {
             ExpandableNotificationRow row = mExpandedBubble.getRowView();
-            if (!row.equals(mExpandedViewContainer.getChildAt(0))) {
+            if (!row.equals(mExpandedViewContainer.getExpandedView())) {
                 // Different expanded view than what we have
                 mExpandedViewContainer.setExpandedView(null);
             }
-            int pointerPosition = mExpandedBubble.getPosition().x
-                    + (mExpandedBubble.getWidth() / 2);
-            mExpandedViewContainer.setPointerPosition(pointerPosition);
             mExpandedViewContainer.setExpandedView(row);
+            mExpandedViewContainer.setHeaderText(null);
         }
+        int pointerPosition = mExpandedBubble.getPosition().x
+                + (mExpandedBubble.getWidth() / 2);
+        mExpandedViewContainer.setPointerPosition(pointerPosition);
     }
 
     private void applyCurrentState() {
+        Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded);
+
         mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
         if (!mIsExpanded) {
             mExpandedViewContainer.setExpandedView(null);
         } else {
             mExpandedViewContainer.setTranslationY(mBubbleContainer.getHeight());
-            ExpandableNotificationRow row = mExpandedBubble.getRowView();
-            applyRowState(row);
+            View expandedView = mExpandedViewContainer.getExpandedView();
+            if (expandedView instanceof ActivityView) {
+                if (expandedView.isAttachedToWindow()) {
+                    ((ActivityView) expandedView).onLocationChanged();
+                }
+            } else {
+                applyRowState(mExpandedBubble.getRowView());
+            }
         }
         int bubbsCount = mBubbleContainer.getChildCount();
         for (int i = 0; i < bubbsCount; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 88030ee..96b2dba 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -33,7 +33,7 @@
  * Handles interpreting touches on a {@link BubbleStackView}. This includes expanding, collapsing,
  * dismissing, and flings.
  */
-public class BubbleTouchHandler implements View.OnTouchListener {
+class BubbleTouchHandler implements View.OnTouchListener {
 
     private BubbleController mController = Dependency.get(BubbleController.class);
     private PipDismissViewController mDismissViewController;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 3307992..c1bbb93 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.bubbles;
 
+import android.app.ActivityView;
 import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Point;
@@ -25,7 +27,9 @@
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.OvalShape;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -37,7 +41,7 @@
 /**
  * A floating object on the screen that has a collapsed and expanded state.
  */
-public class BubbleView extends LinearLayout implements BubbleTouchHandler.FloatingView {
+class BubbleView extends LinearLayout implements BubbleTouchHandler.FloatingView {
     private static final String TAG = "BubbleView";
 
     private Context mContext;
@@ -46,6 +50,8 @@
     private NotificationEntry mEntry;
     private int mBubbleSize;
     private int mIconSize;
+    private PendingIntent mAppOverlayIntent;
+    private ActivityView mActivityView;
 
     public BubbleView(Context context) {
         this(context, null);
@@ -117,12 +123,51 @@
     }
 
     /**
-     * @return the view to display when the bubble is expanded.
+     * @return the view to display notification content when the bubble is expanded.
      */
     public ExpandableNotificationRow getRowView() {
         return mEntry.getRow();
     }
 
+    /**
+     * @return a view used to display app overlay content when expanded.
+     */
+    public ActivityView getActivityView() {
+        if (mActivityView == null) {
+            mActivityView = new ActivityView(mContext);
+            Log.d(TAG, "[getActivityView] created: " + mActivityView);
+        }
+        return mActivityView;
+    }
+
+    /**
+     * Removes and releases an ActivityView if one was previously created for this bubble.
+     */
+    public void destroyActivityView(ViewGroup tmpParent) {
+        if (mActivityView == null) {
+            return;
+        }
+        // HACK: Only release if initialized. There's no way to know if the ActivityView has
+        // been initialized. Calling release() if it hasn't been initialized will crash.
+
+        if (!mActivityView.isAttachedToWindow()) {
+            // HACK: release() will crash if the view is not attached.
+
+            mActivityView.setVisibility(View.GONE);
+            tmpParent.addView(mActivityView, new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT));
+        }
+        try {
+            mActivityView.release();
+        } catch (IllegalStateException ex) {
+            Log.e(TAG, "ActivityView either already released, or not yet initialized.", ex);
+        }
+
+        ((ViewGroup) mActivityView.getParent()).removeView(mActivityView);
+        mActivityView = null;
+    }
+
     @Override
     public void setPosition(int x, int y) {
         setTranslationX(x);
@@ -162,4 +207,20 @@
         lp.height = mBubbleSize;
         v.setLayoutParams(lp);
     }
+
+    /**
+     * @return whether an ActivityView should be used to display the content of this Bubble
+     */
+    public boolean hasAppOverlayIntent() {
+        return mAppOverlayIntent != null;
+    }
+
+    public PendingIntent getAppOverlayIntent() {
+        return mAppOverlayIntent;
+
+    }
+
+    public void setAppOverlayIntent(PendingIntent intent) {
+        mAppOverlayIntent = intent;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 1718cff..4ff27b1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -48,7 +48,7 @@
  *
  * It does not collect touch events when the bouncer shows up.
  */
-public class FalsingManager implements SensorEventListener {
+public class FalsingManager implements SensorEventListener, StateListener {
     private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
 
     private static final int[] CLASSIFIER_SENSORS = new int[] {
@@ -84,8 +84,6 @@
     private boolean mShowingAod;
     private Runnable mPendingWtf;
 
-    private final StateListener mStateListener = this::setStatusBarState;
-
     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
         public void onChange(boolean selfChange) {
@@ -108,7 +106,7 @@
                 UserHandle.USER_ALL);
 
         updateConfiguration();
-        Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).addCallback(this);
     }
 
     public static FalsingManager getInstance(Context context) {
@@ -282,14 +280,15 @@
         updateSessionActive();
     }
 
-    private void setStatusBarState(int state) {
+    @Override
+    public void onStateChanged(int newState) {
         if (FalsingLog.ENABLED) {
             FalsingLog.i("setStatusBarState", new StringBuilder()
                     .append("from=").append(StatusBarState.toShortString(mState))
-                    .append(" to=").append(StatusBarState.toShortString(state))
+                    .append(" to=").append(StatusBarState.toShortString(newState))
                     .toString());
         }
-        mState = state;
+        mState = newState;
         updateSessionActive();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 323cf1f..f14495b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1843,6 +1843,13 @@
      */
     private void handleHide() {
         Trace.beginSection("KeyguardViewMediator#handleHide");
+
+        // It's possible that the device was unlocked in a dream state. It's time to wake up.
+        if (mAodShowing) {
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:BOUNCER_DOZING");
+        }
+
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleHide");
 
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 01ee5ca..6ed1eba 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -52,7 +52,8 @@
 
                         @Suppress("DEPRECATION")
                         override fun onClick(dialog: DialogInterface?, which: Int) {
-                            Dependency.get(ActivityStarter::class.java).startActivity(intent, false)
+                            Dependency.get(ActivityStarter::class.java)
+                                    .postStartActivityDismissingKeyguard(intent, 0)
                         }
                     })
         }
@@ -118,12 +119,13 @@
 
         appName.text = app.applicationName
         if (showIcons) {
-            dialogBuilder.generateIconsForApp(types).forEach {
+            dialogBuilder.generateIconsForApp(types).forEachIndexed { index, it ->
                 it.setBounds(0, 0, iconSize, iconSize)
                 val image = ImageView(context).apply {
                     imageTintList = ColorStateList.valueOf(iconColor)
                     setImageDrawable(it)
                 }
+                image.contentDescription = types[index].getName(context)
                 icons.addView(image, lp)
             }
             icons.visibility = View.VISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index e030e40..e63f88a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -284,10 +284,17 @@
     public void updateEverything() {
         post(() -> {
             updateVisibilities();
+            updateClickabilities();
             setClickable(false);
         });
     }
 
+    private void updateClickabilities() {
+        mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE);
+        mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE);
+        mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE);
+    }
+
     private void updateVisibilities() {
         mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
         mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 40c6039..75ab5df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -141,14 +141,11 @@
     private View mStatusSeparator;
     private ImageView mRingerModeIcon;
     private TextView mRingerModeTextView;
-    private BatteryMeterView mBatteryMeterView;
     private Clock mClockView;
     private DateView mDateView;
     private OngoingPrivacyChip mPrivacyChip;
     private Space mSpace;
     private BatteryMeterView mBatteryRemainingIcon;
-    private TextView mBatteryRemainingText;
-    private boolean mShowBatteryPercentAndEstimate;
 
     private PrivacyItemController mPrivacyItemController;
     /** Counts how many times the long press tooltip has been shown to the user. */
@@ -229,13 +226,6 @@
         // Set the correct tint for the status icons so they contrast
         mIconManager.setTint(fillColor);
 
-        mShowBatteryPercentAndEstimate = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_battery_percentage_setting_available);
-
-        mBatteryMeterView = findViewById(R.id.battery);
-        mBatteryMeterView.setPercentShowMode(mShowBatteryPercentAndEstimate
-                ? BatteryMeterView.MODE_ON : BatteryMeterView.MODE_OFF);
-        mBatteryMeterView.setOnClickListener(this);
         mClockView = findViewById(R.id.clock);
         mClockView.setOnClickListener(this);
         mDateView = findViewById(R.id.date);
@@ -245,13 +235,8 @@
 
         // Tint for the battery icons are handled in setupHost()
         mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
-        mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_OFF);
         // Don't need to worry about tuner settings for this icon
         mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
-
-        mBatteryRemainingText = findViewById(R.id.batteryRemainingText);
-        mBatteryRemainingText.setTextColor(fillColor);
-
         updateShowPercent();
     }
 
@@ -268,10 +253,8 @@
     }
 
     private void setChipVisibility(boolean chipVisible) {
-        mBatteryMeterView.setVisibility(View.VISIBLE);
         if (chipVisible) {
             mPrivacyChip.setVisibility(View.VISIBLE);
-            if (mHasTopCutout) mBatteryMeterView.setVisibility(View.GONE);
         } else {
             mPrivacyChip.setVisibility(View.GONE);
         }
@@ -339,7 +322,6 @@
         // Update color schemes in landscape to use wallpaperTextColor
         boolean shouldUseWallpaperTextColor =
                 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
-        mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
         mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
     }
 
@@ -415,13 +397,6 @@
                 .build();
     }
 
-    private void updateBatteryRemainingText() {
-        if (!mShowBatteryPercentAndEstimate) {
-            return;
-        }
-        mBatteryRemainingText.setText(mBatteryController.getEstimatedTimeRemainingString());
-    }
-
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
@@ -519,7 +494,6 @@
             }
         }
         mSpace.setLayoutParams(lp);
-        // Decide whether to show BatteryMeterView
         setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
         return super.onApplyWindowInsets(insets);
     }
@@ -546,7 +520,6 @@
             mAlarmController.addCallback(this);
             mContext.registerReceiver(mRingerReceiver,
                     new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
-            updateBatteryRemainingText();
         } else {
             mZenController.removeCallback(this);
             mAlarmController.removeCallback(this);
@@ -559,9 +532,6 @@
         if (v == mClockView) {
             mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
                     AlarmClock.ACTION_SHOW_ALARMS),0);
-        } else if (v == mBatteryMeterView) {
-            mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
-                    Intent.ACTION_POWER_USAGE_SUMMARY),0);
         } else if (v == mPrivacyChip) {
             Handler mUiHandler = new Handler(Looper.getMainLooper());
             mUiHandler.post(() -> {
@@ -699,7 +669,7 @@
     }
 
     public void updateEverything() {
-        post(() -> setClickable(false));
+        post(() -> setClickable(!mExpanded));
     }
 
     public void setQSPanel(final QSPanel qsPanel) {
@@ -713,9 +683,6 @@
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
         mHeaderQsPanel.setHost(host, null /* No customization in header */);
 
-        // Use SystemUI context to get battery meter colors, and let it use the default tint (white)
-        mBatteryMeterView.setColorsFromContext(mHost.getContext());
-        mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
 
         Rect tintArea = new Rect(0, 0, 0, 0);
         int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
@@ -763,22 +730,8 @@
                 .getIntForUser(getContext().getContentResolver(),
                         SHOW_BATTERY_PERCENT, 0, ActivityManager.getCurrentUser());
 
-        mShowBatteryPercentAndEstimate = systemSetting;
-
-        updateBatteryViews();
-    }
-
-    private void updateBatteryViews() {
-        if (mShowBatteryPercentAndEstimate) {
-            mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ON);
-            mBatteryRemainingIcon.setVisibility(View.VISIBLE);
-            mBatteryRemainingText.setVisibility(View.VISIBLE);
-            updateBatteryRemainingText();
-        } else {
-            mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_OFF);
-            mBatteryRemainingIcon.setVisibility(View.GONE);
-            mBatteryRemainingText.setVisibility(View.GONE);
-        }
+        mBatteryRemainingIcon.setPercentShowMode(systemSetting
+                ? BatteryMeterView.MODE_ESTIMATE : BatteryMeterView.MODE_ON);
     }
 
     private final class PercentSettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 81757d0..c474faf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -101,6 +101,7 @@
     private float mBackButtonAlpha;
     private MotionEvent mStatusBarGestureDownEvent;
     private float mWindowCornerRadius;
+    private boolean mSupportsRoundedCornersOnWindows;
 
     private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
 
@@ -244,6 +245,18 @@
             }
         }
 
+        public boolean supportsRoundedCornersOnWindows() {
+            if (!verifyCaller("supportsRoundedCornersOnWindows")) {
+                return false;
+            }
+            long token = Binder.clearCallingIdentity();
+            try {
+                return mSupportsRoundedCornersOnWindows;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         private boolean verifyCaller(String reason) {
             final int callerId = Binder.getCallingUserHandle().getIdentifier();
             if (callerId != mCurrentBoundedUserId) {
@@ -353,6 +366,8 @@
         mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS,
                 getDefaultInteractionFlags());
         mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources());
+        mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
+                .supportsRoundedCornersOnWindows(mContext.getResources());
 
         // Listen for the package update changes.
         if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 6a01563..904478e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -111,7 +111,6 @@
     private static final int MSG_SHOW_CHARGING_ANIMATION       = 44 << MSG_SHIFT;
     private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT;
     private static final int MSG_SHOW_PINNING_TOAST_ESCAPE     = 46 << MSG_SHIFT;
-    private static final int MSG_BIOMETRIC_TRY_AGAIN           = 47 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -271,11 +270,10 @@
 
         default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
                 int type, boolean requireConfirmation, int userId) { }
-        default void onBiometricAuthenticated() { }
+        default void onBiometricAuthenticated(boolean authenticated) { }
         default void onBiometricHelp(String message) { }
         default void onBiometricError(String error) { }
         default void hideBiometricDialog() { }
-        default void showBiometricTryAgain() { }
     }
 
     @VisibleForTesting
@@ -736,9 +734,9 @@
     }
 
     @Override
-    public void onBiometricAuthenticated() {
+    public void onBiometricAuthenticated(boolean authenticated) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget();
+            mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, authenticated).sendToTarget();
         }
     }
 
@@ -763,13 +761,6 @@
         }
     }
 
-    @Override
-    public void showBiometricTryAgain() {
-        synchronized (mLock) {
-            mHandler.obtainMessage(MSG_BIOMETRIC_TRY_AGAIN).sendToTarget();
-        }
-    }
-
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -991,7 +982,7 @@
                     break;
                 case MSG_BIOMETRIC_AUTHENTICATED:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).onBiometricAuthenticated();
+                        mCallbacks.get(i).onBiometricAuthenticated((boolean) msg.obj);
                     }
                     break;
                 case MSG_BIOMETRIC_HELP:
@@ -1024,11 +1015,6 @@
                         mCallbacks.get(i).showPinningEscapeToast();
                     }
                     break;
-                case MSG_BIOMETRIC_TRY_AGAIN:
-                    for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).showBiometricTryAgain();
-                    }
-                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 91b34fc..bd9ca1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -55,7 +55,7 @@
  * overflow icons that don't fit into the regular list anymore.
  */
 public class NotificationShelf extends ActivatableNotificationView implements
-        View.OnLayoutChangeListener {
+        View.OnLayoutChangeListener, StateListener {
 
     private static final boolean USE_ANIMATIONS_WHEN_OPENING =
             SystemProperties.getBoolean("debug.icon_opening_animations", true);
@@ -95,8 +95,6 @@
     private int mCutoutHeight;
     private int mGapHeight;
 
-    private final StateListener mStateListener = this::setStatusBarState;
-
     public NotificationShelf(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -121,13 +119,13 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         Dependency.get(StatusBarStateController.class)
-                .addCallback(mStateListener, StatusBarStateController.RANK_SHELF);
+                .addCallback(this, StatusBarStateController.RANK_SHELF);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).removeCallback(this);
     }
 
     public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
@@ -174,6 +172,24 @@
         updateInteractiveness();
     }
 
+    /**
+     * Alpha animation with translation played when this view is visible on AOD.
+     */
+    public void fadeInTranslating() {
+        mShelfIcons.setTranslationY(-mShelfAppearTranslation);
+        mShelfIcons.setAlpha(0);
+        mShelfIcons.animate()
+                .setInterpolator(Interpolators.DECELERATE_QUINT)
+                .translationY(0)
+                .setDuration(SHELF_IN_TRANSLATION_DURATION)
+                .start();
+        mShelfIcons.animate()
+                .alpha(1)
+                .setInterpolator(Interpolators.LINEAR)
+                .setDuration(SHELF_IN_TRANSLATION_DURATION)
+                .start();
+    }
+
     @Override
     protected View getContentView() {
         return mShelfIcons;
@@ -225,7 +241,7 @@
             }
             viewState.hasItemsInStableShelf = lastViewState.inShelf;
             viewState.hidden = !mAmbientState.isShadeExpanded()
-                    || mAmbientState.isQsCustomizerShowing() || mAmbientState.isFullyDark();
+                    || mAmbientState.isQsCustomizerShowing();
             viewState.maxShelfEnd = maxShelfEnd;
         } else {
             viewState.hidden = true;
@@ -420,7 +436,7 @@
         float maxTop = row.getTranslationY();
         StatusBarIconView icon = row.getEntry().expandedIcon;
         float shelfIconPosition = getTranslationY() + icon.getTop() + icon.getTranslationY();
-        if (shelfIconPosition < maxTop) {
+        if (shelfIconPosition < maxTop && !mAmbientState.isDark()) {
             int top = (int) (maxTop - shelfIconPosition);
             Rect clipRect = new Rect(0, top, icon.getWidth(), Math.max(top, icon.getHeight()));
             icon.setClipBounds(clipRect);
@@ -431,7 +447,7 @@
 
     private void updateContinuousClipping(final ExpandableNotificationRow row) {
         StatusBarIconView icon = row.getEntry().expandedIcon;
-        boolean needsContinuousClipping = ViewState.isAnimatingY(icon);
+        boolean needsContinuousClipping = ViewState.isAnimatingY(icon) && !mAmbientState.isDark();
         boolean isContinuousClipping = icon.getTag(TAG_CONTINUOUS_CLIPPING) != null;
         if (needsContinuousClipping && !isContinuousClipping) {
             final ViewTreeObserver observer = icon.getViewTreeObserver();
@@ -622,7 +638,9 @@
             iconState.translateContent = false;
         }
         float transitionAmount;
-        if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
+        if (mAmbientState.isDarkAtAll() && !row.isInShelf()) {
+            transitionAmount = mAmbientState.isFullyDark() ? 1 : 0;
+        } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
                 || iconState.useLinearTransitionAmount) {
             transitionAmount = iconTransitionAmount;
         } else {
@@ -860,8 +878,9 @@
         mCollapsedIcons.addOnLayoutChangeListener(this);
     }
 
-    private void setStatusBarState(int statusBarState) {
-        mStatusBarState = statusBarState;
+    @Override
+    public void onStateChanged(int newState) {
+        mStatusBarState = newState;
         updateInteractiveness();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
deleted file mode 100644
index 6d2c001..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * Copyright (C) 2011 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 static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
-import static android.app.StatusBarManager.DISABLE_NONE;
-
-import android.annotation.DrawableRes;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.telephony.SubscriptionInfo;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import com.android.settingslib.graph.SignalDrawable;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.IconLogger;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.Utils.DisableStateTracker;
-
-import java.util.ArrayList;
-import java.util.List;
-
-// Intimately tied to the design of res/layout/signal_cluster_view.xml
-public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
-        SecurityController.SecurityControllerCallback, Tunable, DarkReceiver {
-
-    static final String TAG = "SignalClusterView";
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private static final String SLOT_AIRPLANE = "airplane";
-    private static final String SLOT_MOBILE = "mobile";
-    private static final String SLOT_WIFI = "wifi";
-    private static final String SLOT_ETHERNET = "ethernet";
-    private static final String SLOT_VPN = "vpn";
-
-    private final NetworkController mNetworkController;
-    private final SecurityController mSecurityController;
-
-    private boolean mVpnVisible = false;
-    private int mVpnIconId = 0;
-    private int mLastVpnIconId = -1;
-    private boolean mEthernetVisible = false;
-    private int mEthernetIconId = 0;
-    private int mLastEthernetIconId = -1;
-    private boolean mWifiVisible = false;
-    private int mWifiStrengthId = 0;
-    private int mLastWifiStrengthId = -1;
-    private boolean mWifiIn;
-    private boolean mWifiOut;
-    private boolean mIsAirplaneMode = false;
-    private int mAirplaneIconId = 0;
-    private int mLastAirplaneIconId = -1;
-    private String mAirplaneContentDescription;
-    private String mWifiDescription;
-    private String mEthernetDescription;
-    private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
-    private int mIconTint = Color.WHITE;
-    private float mDarkIntensity;
-    private final Rect mTintArea = new Rect();
-
-    ViewGroup mEthernetGroup, mWifiGroup;
-    ImageView mVpn, mEthernet, mWifi, mAirplane, mEthernetDark, mWifiDark;
-    ImageView mWifiActivityIn;
-    ImageView mWifiActivityOut;
-    View mWifiAirplaneSpacer;
-    View mWifiSignalSpacer;
-    LinearLayout mMobileSignalGroup;
-
-    private final int mMobileSignalGroupEndPadding;
-    private final int mMobileDataIconStartPadding;
-    private final int mSecondaryTelephonyPadding;
-    private final int mEndPadding;
-    private final int mEndPaddingNothingVisible;
-    private final float mIconScaleFactor;
-
-    private boolean mBlockAirplane;
-    private boolean mBlockMobile;
-    private boolean mBlockWifi;
-    private boolean mBlockEthernet;
-    private boolean mActivityEnabled;
-    private boolean mForceBlockWifi;
-
-    private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
-
-    public SignalClusterView(Context context) {
-        this(context, null);
-    }
-
-    public SignalClusterView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        Resources res = getResources();
-        mMobileSignalGroupEndPadding =
-                res.getDimensionPixelSize(R.dimen.mobile_signal_group_end_padding);
-        mMobileDataIconStartPadding =
-                res.getDimensionPixelSize(R.dimen.mobile_data_icon_start_padding);
-        mSecondaryTelephonyPadding = res.getDimensionPixelSize(R.dimen.secondary_telephony_padding);
-        mEndPadding = res.getDimensionPixelSize(R.dimen.signal_cluster_battery_padding);
-        mEndPaddingNothingVisible = res.getDimensionPixelSize(
-                R.dimen.no_signal_cluster_battery_padding);
-
-        TypedValue typedValue = new TypedValue();
-        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
-        mIconScaleFactor = typedValue.getFloat();
-        mNetworkController = Dependency.get(NetworkController.class);
-        mSecurityController = Dependency.get(SecurityController.class);
-        addOnAttachStateChangeListener(
-                new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
-        updateActivityEnabled();
-    }
-
-    public void setForceBlockWifi() {
-        mForceBlockWifi = true;
-        mBlockWifi = true;
-        if (isAttachedToWindow()) {
-            // Re-register to get new callbacks.
-            mNetworkController.removeCallback(this);
-            mNetworkController.addCallback(this);
-        }
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
-            return;
-        }
-        ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(newValue);
-        boolean blockAirplane = blockList.contains(SLOT_AIRPLANE);
-        boolean blockMobile = blockList.contains(SLOT_MOBILE);
-        boolean blockWifi = blockList.contains(SLOT_WIFI);
-        boolean blockEthernet = blockList.contains(SLOT_ETHERNET);
-
-        if (blockAirplane != mBlockAirplane || blockMobile != mBlockMobile
-                || blockEthernet != mBlockEthernet || blockWifi != mBlockWifi) {
-            mBlockAirplane = blockAirplane;
-            mBlockMobile = blockMobile;
-            mBlockEthernet = blockEthernet;
-            mBlockWifi = blockWifi || mForceBlockWifi;
-            // Re-register to get new callbacks.
-            mNetworkController.removeCallback(this);
-            mNetworkController.addCallback(this);
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mVpn            = findViewById(R.id.vpn);
-        mEthernetGroup  = findViewById(R.id.ethernet_combo);
-        mEthernet       = findViewById(R.id.ethernet);
-        mEthernetDark   = findViewById(R.id.ethernet_dark);
-        mWifiGroup      = findViewById(R.id.wifi_combo);
-        mWifi           = findViewById(R.id.wifi_signal);
-        mWifiDark       = findViewById(R.id.wifi_signal_dark);
-        mWifiActivityIn = findViewById(R.id.wifi_in);
-        mWifiActivityOut= findViewById(R.id.wifi_out);
-        mAirplane       = findViewById(R.id.airplane);
-        mWifiAirplaneSpacer =         findViewById(R.id.wifi_airplane_spacer);
-        mWifiSignalSpacer =           findViewById(R.id.wifi_signal_spacer);
-        mMobileSignalGroup =          findViewById(R.id.mobile_signal_group);
-
-        maybeScaleVpnAndNoSimsIcons();
-    }
-
-    /**
-     * Extracts the icon off of the VPN and no sims views and maybe scale them by
-     * {@link #mIconScaleFactor}. Note that the other icons are not scaled here because they are
-     * dynamic. As such, they need to be scaled each time the icon changes in {@link #apply()}.
-     */
-    private void maybeScaleVpnAndNoSimsIcons() {
-        if (mIconScaleFactor == 1.f) {
-            return;
-        }
-
-        mVpn.setImageDrawable(new ScalingDrawableWrapper(mVpn.getDrawable(), mIconScaleFactor));
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mVpnVisible = mSecurityController.isVpnEnabled();
-        mVpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
-
-        for (PhoneState state : mPhoneStates) {
-            if (state.mMobileGroup.getParent() == null) {
-                mMobileSignalGroup.addView(state.mMobileGroup);
-            }
-        }
-
-        int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
-        mMobileSignalGroup.setPaddingRelative(0, 0, endPadding, 0);
-
-        Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
-
-        apply();
-        applyIconTint();
-        mNetworkController.addCallback(this);
-        mSecurityController.addCallback(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mMobileSignalGroup.removeAllViews();
-        Dependency.get(TunerService.class).removeTunable(this);
-        mSecurityController.removeCallback(this);
-        mNetworkController.removeCallback(this);
-
-        super.onDetachedFromWindow();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-
-        // Re-run all checks against the tint area for all icons
-        applyIconTint();
-    }
-
-    // From SecurityController.
-    @Override
-    public void onStateChanged() {
-        post(new Runnable() {
-            @Override
-            public void run() {
-                mVpnVisible = mSecurityController.isVpnEnabled();
-                mVpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
-                apply();
-            }
-        });
-    }
-
-    private void updateActivityEnabled() {
-        mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
-    }
-
-    @Override
-    public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-            boolean activityIn, boolean activityOut, String description, boolean isTransient,
-            String secondaryLabel) {
-        mWifiVisible = statusIcon.visible && !mBlockWifi;
-        mWifiStrengthId = statusIcon.icon;
-        mWifiDescription = statusIcon.contentDescription;
-        mWifiIn = activityIn && mActivityEnabled && mWifiVisible;
-        mWifiOut = activityOut && mActivityEnabled && mWifiVisible;
-
-        apply();
-    }
-
-    @Override
-    public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
-            int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
-            String description, boolean isWide, int subId, boolean roaming) {
-        PhoneState state = getState(subId);
-        if (state == null) {
-            return;
-        }
-        state.mMobileVisible = statusIcon.visible && !mBlockMobile;
-        state.mMobileStrengthId = statusIcon.icon;
-        state.mMobileTypeId = statusType;
-        state.mMobileDescription = statusIcon.contentDescription;
-        state.mMobileTypeDescription = typeContentDescription;
-        state.mRoaming = roaming;
-        state.mActivityIn = activityIn && mActivityEnabled;
-        state.mActivityOut = activityOut && mActivityEnabled;
-
-        apply();
-    }
-
-    @Override
-    public void setEthernetIndicators(IconState state) {
-        mEthernetVisible = state.visible && !mBlockEthernet;
-        mEthernetIconId = state.icon;
-        mEthernetDescription = state.contentDescription;
-
-        apply();
-    }
-
-    @Override
-    public void setNoSims(boolean show, boolean simDetected) {
-        // Noop. Status bar no longer shows no sim icon.
-    }
-
-    @Override
-    public void setSubs(List<SubscriptionInfo> subs) {
-        if (hasCorrectSubs(subs)) {
-            return;
-        }
-        mPhoneStates.clear();
-        if (mMobileSignalGroup != null) {
-            mMobileSignalGroup.removeAllViews();
-        }
-        final int n = subs.size();
-        for (int i = 0; i < n; i++) {
-            inflatePhoneState(subs.get(i).getSubscriptionId());
-        }
-        if (isAttachedToWindow()) {
-            applyIconTint();
-        }
-    }
-
-    private boolean hasCorrectSubs(List<SubscriptionInfo> subs) {
-        final int N = subs.size();
-        if (N != mPhoneStates.size()) {
-            return false;
-        }
-        for (int i = 0; i < N; i++) {
-            if (mPhoneStates.get(i).mSubId != subs.get(i).getSubscriptionId()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private PhoneState getState(int subId) {
-        for (PhoneState state : mPhoneStates) {
-            if (state.mSubId == subId) {
-                return state;
-            }
-        }
-        Log.e(TAG, "Unexpected subscription " + subId);
-        return null;
-    }
-
-    private PhoneState inflatePhoneState(int subId) {
-        PhoneState state = new PhoneState(subId, mContext);
-        if (mMobileSignalGroup != null) {
-            mMobileSignalGroup.addView(state.mMobileGroup);
-        }
-        mPhoneStates.add(state);
-        return state;
-    }
-
-    @Override
-    public void setIsAirplaneMode(IconState icon) {
-        mIsAirplaneMode = icon.visible && !mBlockAirplane;
-        mAirplaneIconId = icon.icon;
-        mAirplaneContentDescription = icon.contentDescription;
-
-        apply();
-    }
-
-    @Override
-    public void setMobileDataEnabled(boolean enabled) {
-        // Don't care.
-    }
-
-    @Override
-    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
-        // Standard group layout onPopulateAccessibilityEvent() implementations
-        // ignore content description, so populate manually
-        if (mEthernetVisible && mEthernetGroup != null &&
-                mEthernetGroup.getContentDescription() != null)
-            event.getText().add(mEthernetGroup.getContentDescription());
-        if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
-            event.getText().add(mWifiGroup.getContentDescription());
-        for (PhoneState state : mPhoneStates) {
-            state.populateAccessibilityEvent(event);
-        }
-        return super.dispatchPopulateAccessibilityEventInternal(event);
-    }
-
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        super.onRtlPropertiesChanged(layoutDirection);
-
-        if (mEthernet != null) {
-            mEthernet.setImageDrawable(null);
-            mEthernetDark.setImageDrawable(null);
-            mLastEthernetIconId = -1;
-        }
-
-        if (mWifi != null) {
-            mWifi.setImageDrawable(null);
-            mWifiDark.setImageDrawable(null);
-            mLastWifiStrengthId = -1;
-        }
-
-        for (PhoneState state : mPhoneStates) {
-            if (state.mMobileType != null) {
-                state.mMobileType.setImageDrawable(null);
-                state.mLastMobileTypeId = -1;
-            }
-        }
-
-        if (mAirplane != null) {
-            mAirplane.setImageDrawable(null);
-            mLastAirplaneIconId = -1;
-        }
-
-        apply();
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    // Run after each indicator change.
-    private void apply() {
-        if (mWifiGroup == null) return;
-
-        if (mVpnVisible) {
-            if (mLastVpnIconId != mVpnIconId) {
-                setIconForView(mVpn, mVpnIconId);
-                mLastVpnIconId = mVpnIconId;
-            }
-            mIconLogger.onIconShown(SLOT_VPN);
-            mVpn.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_VPN);
-            mVpn.setVisibility(View.GONE);
-        }
-        if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
-
-        if (mEthernetVisible) {
-            if (mLastEthernetIconId != mEthernetIconId) {
-                setIconForView(mEthernet, mEthernetIconId);
-                setIconForView(mEthernetDark, mEthernetIconId);
-                mLastEthernetIconId = mEthernetIconId;
-            }
-            mEthernetGroup.setContentDescription(mEthernetDescription);
-            mIconLogger.onIconShown(SLOT_ETHERNET);
-            mEthernetGroup.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_ETHERNET);
-            mEthernetGroup.setVisibility(View.GONE);
-        }
-
-        if (DEBUG) Log.d(TAG,
-                String.format("ethernet: %s",
-                    (mEthernetVisible ? "VISIBLE" : "GONE")));
-
-        if (mWifiVisible) {
-            if (mWifiStrengthId != mLastWifiStrengthId) {
-                setIconForView(mWifi, mWifiStrengthId);
-                setIconForView(mWifiDark, mWifiStrengthId);
-                mLastWifiStrengthId = mWifiStrengthId;
-            }
-            mIconLogger.onIconShown(SLOT_WIFI);
-            mWifiGroup.setContentDescription(mWifiDescription);
-            mWifiGroup.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_WIFI);
-            mWifiGroup.setVisibility(View.GONE);
-        }
-
-        if (DEBUG) Log.d(TAG,
-                String.format("wifi: %s sig=%d",
-                    (mWifiVisible ? "VISIBLE" : "GONE"),
-                    mWifiStrengthId));
-
-        mWifiActivityIn.setVisibility(mWifiIn ? View.VISIBLE : View.GONE);
-        mWifiActivityOut.setVisibility(mWifiOut ? View.VISIBLE : View.GONE);
-
-        boolean anyMobileVisible = false;
-        int firstMobileTypeId = 0;
-        for (PhoneState state : mPhoneStates) {
-            if (state.apply(anyMobileVisible)) {
-                if (!anyMobileVisible) {
-                    firstMobileTypeId = state.mMobileTypeId;
-                    anyMobileVisible = true;
-                }
-            }
-        }
-        if (anyMobileVisible) {
-            mIconLogger.onIconShown(SLOT_MOBILE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_MOBILE);
-        }
-
-        if (mIsAirplaneMode) {
-            if (mLastAirplaneIconId != mAirplaneIconId) {
-                setIconForView(mAirplane, mAirplaneIconId);
-                mLastAirplaneIconId = mAirplaneIconId;
-            }
-            mAirplane.setContentDescription(mAirplaneContentDescription);
-            mIconLogger.onIconShown(SLOT_AIRPLANE);
-            mAirplane.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_AIRPLANE);
-            mAirplane.setVisibility(View.GONE);
-        }
-
-        if (mIsAirplaneMode && mWifiVisible) {
-            mWifiAirplaneSpacer.setVisibility(View.VISIBLE);
-        } else {
-            mWifiAirplaneSpacer.setVisibility(View.GONE);
-        }
-
-        if ((anyMobileVisible && firstMobileTypeId != 0) && mWifiVisible) {
-            mWifiSignalSpacer.setVisibility(View.VISIBLE);
-        } else {
-            mWifiSignalSpacer.setVisibility(View.GONE);
-        }
-
-        boolean anythingVisible = mWifiVisible || mIsAirplaneMode
-                || anyMobileVisible || mVpnVisible || mEthernetVisible;
-        setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
-    }
-
-    /**
-     * Sets the given drawable id on the view. This method will also scale the icon by
-     * {@link #mIconScaleFactor} if appropriate.
-     */
-    private void setIconForView(ImageView imageView, @DrawableRes int iconId) {
-        // Using the imageView's context to retrieve the Drawable so that theme is preserved.
-        Drawable icon = imageView.getContext().getDrawable(iconId);
-
-        if (mIconScaleFactor == 1.f) {
-            imageView.setImageDrawable(icon);
-        } else {
-            imageView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor));
-        }
-    }
-
-
-    @Override
-    public void onDarkChanged(Rect tintArea, float darkIntensity, int tint) {
-        boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
-                || !mTintArea.equals(tintArea);
-        mIconTint = tint;
-        mDarkIntensity = darkIntensity;
-        mTintArea.set(tintArea);
-        if (changed && isAttachedToWindow()) {
-            applyIconTint();
-        }
-    }
-
-    private void applyIconTint() {
-        setTint(mVpn, DarkIconDispatcher.getTint(mTintArea, mVpn, mIconTint));
-        setTint(mAirplane, DarkIconDispatcher.getTint(mTintArea, mAirplane, mIconTint));
-        applyDarkIntensity(
-                DarkIconDispatcher.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
-                mWifi, mWifiDark);
-        setTint(mWifiActivityIn,
-                DarkIconDispatcher.getTint(mTintArea, mWifiActivityIn, mIconTint));
-        setTint(mWifiActivityOut,
-                DarkIconDispatcher.getTint(mTintArea, mWifiActivityOut, mIconTint));
-        applyDarkIntensity(
-                DarkIconDispatcher.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
-                mEthernet, mEthernetDark);
-        for (int i = 0; i < mPhoneStates.size(); i++) {
-            mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea);
-        }
-    }
-
-    private void applyDarkIntensity(float darkIntensity, View lightIcon, View darkIcon) {
-        lightIcon.setAlpha(1 - darkIntensity);
-        darkIcon.setAlpha(darkIntensity);
-    }
-
-    private void setTint(ImageView v, int tint) {
-        v.setImageTintList(ColorStateList.valueOf(tint));
-    }
-
-    private int currentVpnIconId(boolean isBranded) {
-        return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic;
-    }
-
-    private class PhoneState {
-        private final int mSubId;
-        private boolean mMobileVisible = false;
-        private int mMobileStrengthId = 0, mMobileTypeId = 0;
-        private int mLastMobileStrengthId = -1;
-        private int mLastMobileTypeId = -1;
-        private String mMobileDescription, mMobileTypeDescription;
-
-        private ViewGroup mMobileGroup;
-        private ImageView mMobile, mMobileType, mMobileRoaming;
-        private View mMobileRoamingSpace;
-        public boolean mRoaming;
-        private ImageView mMobileActivityIn;
-        private ImageView mMobileActivityOut;
-        public boolean mActivityIn;
-        public boolean mActivityOut;
-        private SignalDrawable mMobileSignalDrawable;
-
-        public PhoneState(int subId, Context context) {
-            ViewGroup root = (ViewGroup) LayoutInflater.from(context)
-                    .inflate(R.layout.mobile_signal_group, null);
-            setViews(root);
-            mSubId = subId;
-        }
-
-        public void setViews(ViewGroup root) {
-            mMobileGroup    = root;
-            mMobile         = root.findViewById(R.id.mobile_signal);
-            mMobileType     = root.findViewById(R.id.mobile_type);
-            mMobileRoaming  = root.findViewById(R.id.mobile_roaming);
-            mMobileRoamingSpace  = root.findViewById(R.id.mobile_roaming_space);
-            mMobileActivityIn = root.findViewById(R.id.mobile_in);
-            mMobileActivityOut = root.findViewById(R.id.mobile_out);
-            mMobileSignalDrawable = new SignalDrawable(mMobile.getContext());
-            mMobile.setImageDrawable(mMobileSignalDrawable);
-        }
-
-        public boolean apply(boolean isSecondaryIcon) {
-            if (mMobileVisible && !mIsAirplaneMode) {
-                if (mLastMobileStrengthId != mMobileStrengthId) {
-                    mMobile.getDrawable().setLevel(mMobileStrengthId);
-                    mLastMobileStrengthId = mMobileStrengthId;
-                }
-
-                if (mLastMobileTypeId != mMobileTypeId) {
-                    mMobileType.setImageResource(mMobileTypeId);
-                    mLastMobileTypeId = mMobileTypeId;
-                }
-
-                mMobileGroup.setContentDescription(mMobileTypeDescription
-                        + " " + mMobileDescription);
-                mMobileGroup.setVisibility(View.VISIBLE);
-            } else {
-                mMobileGroup.setVisibility(View.GONE);
-            }
-
-            // When this isn't next to wifi, give it some extra padding between the signals.
-            mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,
-                    0, 0, 0);
-            mMobile.setPaddingRelative(mMobileDataIconStartPadding, 0, 0, 0);
-
-            if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
-                        (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
-
-            mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
-            mMobileRoaming.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
-            mMobileRoamingSpace.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
-            mMobileActivityIn.setVisibility(mActivityIn ? View.VISIBLE : View.GONE);
-            mMobileActivityOut.setVisibility(mActivityOut ? View.VISIBLE : View.GONE);
-
-            return mMobileVisible;
-        }
-
-        public void populateAccessibilityEvent(AccessibilityEvent event) {
-            if (mMobileVisible && mMobileGroup != null
-                    && mMobileGroup.getContentDescription() != null) {
-                event.getText().add(mMobileGroup.getContentDescription());
-            }
-        }
-
-        public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
-            mMobileSignalDrawable.setDarkIntensity(darkIntensity);
-            setTint(mMobileType, DarkIconDispatcher.getTint(tintArea, mMobileType, tint));
-            setTint(mMobileRoaming, DarkIconDispatcher.getTint(tintArea, mMobileRoaming,
-                    tint));
-            setTint(mMobileActivityIn,
-                    DarkIconDispatcher.getTint(tintArea, mMobileActivityIn, tint));
-            setTint(mMobileActivityOut,
-                    DarkIconDispatcher.getTint(tintArea, mMobileActivityOut, tint));
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java
deleted file mode 100644
index 0652227..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java
+++ /dev/null
@@ -1,34 +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.statusbar;
-
-import com.android.internal.statusbar.StatusBarIcon;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Holds an array of {@link com.android.internal.statusbar.StatusBarIcon}s and draws them
- * in a linear layout
- */
-public class StatusBarIconContainer {
-    private final List<StatusBarIcon> mIcons = new ArrayList<>();
-
-    public StatusBarIconContainer(List<StatusBarIcon> icons) {
-        mIcons.addAll(icons);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3c13354..19ed13e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -206,6 +206,10 @@
         mIconScale = SYSTEM_ICON_SCALE;
     }
 
+    public float getIconScaleFullyDark() {
+        return (float) mStatusBarIconDrawingSizeDark / mStatusBarIconDrawingSize;
+    }
+
     public float getIconScale() {
         return mIconScale;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index 087b655..54bce1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -331,7 +331,8 @@
          *
          * @param newState the new {@link StatusBarState}
          */
-        public void onStateChanged(int newState);
+        default void onStateChanged(int newState) {
+        }
 
         /**
          * Callback to be notified when Dozing changes. Dozing is stored separately from state.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index e698e64..45db002 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,7 +18,6 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
-import android.os.Handler;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
@@ -51,7 +50,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
 
 /**
  * NotificationEntryManager is responsible for the adding, removing, and updating of notifications.
@@ -64,11 +62,10 @@
         NotificationUpdateHandler,
         VisualStabilityManager.Callback {
     private static final String TAG = "NotificationEntryMgr";
-    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    public static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
-
-    protected final Context mContext;
+    private final Context mContext;
+    @VisibleForTesting
     protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
 
     private final DeviceProvisionedController mDeviceProvisionedController =
@@ -80,13 +77,11 @@
     private NotificationRemoteInputManager mRemoteInputManager;
     private NotificationRowBinder mNotificationRowBinder;
 
-    private final Handler mDeferredNotificationViewUpdateHandler;
-    private Runnable mUpdateNotificationViewsCallback;
-
     private NotificationPresenter mPresenter;
     private NotificationListenerService.RankingMap mLatestRankingMap;
+    @VisibleForTesting
     protected NotificationData mNotificationData;
-    protected NotificationListContainer mListContainer;
+    private NotificationListContainer mListContainer;
     @VisibleForTesting
     final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
             = new ArrayList<>();
@@ -121,7 +116,6 @@
     public NotificationEntryManager(Context context) {
         mContext = context;
         mNotificationData = new NotificationData();
-        mDeferredNotificationViewUpdateHandler = new Handler();
     }
 
     /** Adds a {@link NotificationEntryListener}. */
@@ -156,7 +150,6 @@
             NotificationListContainer listContainer,
             HeadsUpManager headsUpManager) {
         mPresenter = presenter;
-        mUpdateNotificationViewsCallback = mPresenter::updateNotificationViews;
         mNotificationData.setHeadsUpManager(headsUpManager);
         mListContainer = listContainer;
 
@@ -180,14 +173,6 @@
         return mNotificationData;
     }
 
-    protected Context getContext() {
-        return mContext;
-    }
-
-    protected NotificationPresenter getPresenter() {
-        return mPresenter;
-    }
-
     @Override
     public void onReorderingAllowed() {
         updateNotifications();
@@ -229,15 +214,6 @@
         }
     }
 
-    private void maybeScheduleUpdateNotificationViews(NotificationEntry entry) {
-        long audibleAlertTimeout = RECENTLY_ALERTED_THRESHOLD_MS
-                - (System.currentTimeMillis() - entry.lastAudiblyAlertedMs);
-        if (audibleAlertTimeout > 0) {
-            mDeferredNotificationViewUpdateHandler.postDelayed(
-                    mUpdateNotificationViewsCallback, audibleAlertTimeout);
-        }
-    }
-
     @Override
     public void onAsyncInflationFinished(NotificationEntry entry,
             @InflationFlag int inflatedFlags) {
@@ -256,7 +232,6 @@
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onNotificationAdded(entry);
                 }
-                maybeScheduleUpdateNotificationViews(entry);
             } else {
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onEntryReinflated(entry);
@@ -463,8 +438,6 @@
         for (NotificationEntryListener listener : mNotificationEntryListeners) {
             listener.onPostEntryUpdated(entry);
         }
-
-        maybeScheduleUpdateNotificationViews(entry);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9e0dd84..95bd1ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -86,7 +86,6 @@
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -106,6 +105,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 
@@ -122,6 +122,7 @@
     private static final int MENU_VIEW_INDEX = 0;
     private static final String TAG = "ExpandableNotifRow";
     public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
+    private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
     private boolean mUpdateBackgroundOnUpdate;
 
     /**
@@ -1693,17 +1694,31 @@
     /** Sets the last time the notification being displayed audibly alerted the user. */
     public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
         if (NotificationUtils.useNewInterruptionModel(mContext)) {
-            boolean recentlyAudiblyAlerted = System.currentTimeMillis() - lastAudiblyAlertedMs
-                    < NotificationEntryManager.RECENTLY_ALERTED_THRESHOLD_MS;
-            if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
-                mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(
-                        recentlyAudiblyAlerted);
+            long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
+            boolean alertedRecently =
+                    timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
+
+            applyAudiblyAlertedRecently(alertedRecently);
+
+            removeCallbacks(mExpireRecentlyAlertedFlag);
+            if (alertedRecently) {
+                long timeUntilNoLongerRecent =
+                        RECENTLY_ALERTED_THRESHOLD_MS - timeSinceAlertedAudibly;
+                postDelayed(mExpireRecentlyAlertedFlag, timeUntilNoLongerRecent);
             }
-            mPrivateLayout.setRecentlyAudiblyAlerted(recentlyAudiblyAlerted);
-            mPublicLayout.setRecentlyAudiblyAlerted(recentlyAudiblyAlerted);
         }
     }
 
+    private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false);
+
+    private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) {
+        if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
+            mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+        }
+        mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+        mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+    }
+
     public View.OnClickListener getAppOpsOnClickListener() {
         return mOnAppOpsClickListener;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
index 607d96d..6df72fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
@@ -20,11 +20,13 @@
         .USER_SENTIMENT_NEGATIVE;
 
 import android.content.Context;
+import android.metrics.LogMaker;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -58,6 +60,8 @@
      */
     private boolean mIsShadeExpanded;
 
+    private MetricsLogger mMetricsLogger = new MetricsLogger();
+
     @Inject
     public NotificationBlockingHelperManager(Context context) {
         mContext = context;
@@ -100,6 +104,11 @@
             mBlockingHelperRow = row;
             mBlockingHelperRow.setBlockingHelperShowing(true);
 
+            // Log triggering of blocking helper by the system. This log line
+            // should be emitted before the "display" log line.
+            mMetricsLogger.write(
+                    getLogMaker().setSubtype(MetricsEvent.BLOCKING_HELPER_TRIGGERED_BY_SYSTEM));
+
             // We don't care about the touch origin (x, y) since we're opening guts without any
             // explicit user interaction.
             manager.openGuts(mBlockingHelperRow, 0, 0, menuRow.getLongpressMenuItem(mContext));
@@ -153,6 +162,13 @@
                 || mNonBlockablePkgs.contains(makeChannelKey(packageName, channelName));
     }
 
+    private LogMaker getLogMaker() {
+        return mBlockingHelperRow.getStatusBarNotification()
+            .getLogMaker()
+            .setCategory(MetricsEvent.NOTIFICATION_ITEM)
+            .setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER);
+    }
+
     // Format must stay in sync with frameworks/base/core/res/res/values/config.xml
     // config_nonBlockableNotificationPackages
     private String makeChannelKey(String pkg, String channel) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index bf30cf9..c161da3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1489,7 +1489,7 @@
                 }
             }
         }
-        if (mHeadsUpChild != null) {
+        if (mHeadsUpChild != null && mSmartReplyConstants.getShowInHeadsUp()) {
             mHeadsUpSmartReplyView =
                     applySmartReplyView(mHeadsUpChild, smartRepliesAndActions, entry);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index b1eab80..5253e38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -123,11 +123,15 @@
     private OnClickListener mOnKeepShowing = v -> {
         mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
         closeControls(v);
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
     };
 
     private OnClickListener mOnToggleSilent = v -> {
         Runnable saveImportance = () -> {
             swapContent(ACTION_TOGGLE_SILENT, true /* animate */);
+            mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                    .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME));
         };
         if (mCheckSaveListener != null) {
             mCheckSaveListener.checkSave(saveImportance, mSbn);
@@ -139,6 +143,8 @@
     private OnClickListener mOnStopOrMinimizeNotifications = v -> {
         Runnable saveImportance = () -> {
             swapContent(ACTION_BLOCK, true /* animate */);
+            mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                    .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED));
         };
         if (mCheckSaveListener != null) {
             mCheckSaveListener.checkSave(saveImportance, mSbn);
@@ -153,6 +159,8 @@
         logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
         mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
         swapContent(ACTION_UNDO, true /* animate */);
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
     };
 
     public NotificationInfo(Context context, AttributeSet attrs) {
@@ -251,6 +259,9 @@
         bindHeader();
         bindPrompt();
         bindButtons();
+
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_DISPLAY));
     }
 
     private void bindHeader() throws RemoteException {
@@ -588,6 +599,8 @@
         confirmation.setAlpha(1f);
         header.setVisibility(VISIBLE);
         header.setAlpha(1f);
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_DISMISS));
     }
 
     @Override
@@ -733,4 +746,8 @@
             }
         }
     }
+
+    private LogMaker getLogMaker() {
+        return mSbn.getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 80db6c1..2d1f989 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -113,6 +113,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationSnooze;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
@@ -430,7 +431,7 @@
     private int mHeadsUpInset;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private NotificationIconAreaController mIconAreaController;
-    private float mVerticalPanelTranslation;
+    private float mHorizontalPanelTranslation;
     private final NotificationLockscreenUserManager mLockscreenUserManager =
             Dependency.get(NotificationLockscreenUserManager.class);
     protected final NotificationGutsManager mGutsManager =
@@ -458,6 +459,10 @@
 
     private final NotificationGutsManager
             mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+    /**
+     * If the {@link NotificationShelf} should be visible when dark.
+     */
+    private boolean mShowDarkShelf;
 
     @Inject
     public NotificationStackScrollLayout(
@@ -1196,7 +1201,7 @@
             mIsClipped = clipped;
         }
 
-        if (mPulsing) {
+        if (mPulsing || mAmbientState.isFullyDark() && mShowDarkShelf) {
             setClipBounds(null);
         } else if (mAmbientState.isDarkAtAll()) {
             setClipBounds(mBackgroundAnimationRect);
@@ -4361,6 +4366,9 @@
         if (mAmbientState.isDark() == dark) {
             return;
         }
+        if (!dark) {
+            mShowDarkShelf = false;
+        }
         mAmbientState.setDark(dark);
         if (animate && mAnimationsEnabled) {
             mDarkNeedsAnimation = true;
@@ -4377,12 +4385,12 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void updatePanelTranslation() {
-        setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
+        setTranslationX(mHorizontalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setVerticalPanelTranslation(float verticalPanelTranslation) {
-        mVerticalPanelTranslation = verticalPanelTranslation;
+    public void setHorizontalPanelTranslation(float verticalPanelTranslation) {
+        mHorizontalPanelTranslation = verticalPanelTranslation;
         updatePanelTranslation();
     }
 
@@ -4422,9 +4430,9 @@
         boolean nowDarkAtAll = mAmbientState.isDarkAtAll();
         if (nowFullyDark != wasFullyDark) {
             updateContentHeight();
-        }
-        if (mIconAreaController != null) {
-            mIconAreaController.setDarkAmount(interpolatedDarkAmount);
+            if (nowFullyDark && mShowDarkShelf) {
+                updateDarkShelfVisibility();
+            }
         }
         if (!wasDarkAtAll && nowDarkAtAll) {
             resetExposedMenuView(true /* animate */, true /* animate */);
@@ -4435,6 +4443,22 @@
         requestChildrenUpdate();
     }
 
+    /**
+     * If the shelf should be visible when the device is in ambient mode (dozing.)
+     */
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    public void setShowDarkShelf(boolean showDarkShelf) {
+        mShowDarkShelf = showDarkShelf;
+    }
+
+    private void updateDarkShelfVisibility() {
+        DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
+        if (dozeParameters.shouldControlScreenOff()) {
+            mShelf.fadeInTranslating();
+        }
+        updateClipping();
+    }
+
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     public void notifyDarkAnimationStart(boolean dark) {
         // We only swap the scaling factor if we're fully dark or fully awake to avoid
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index f907b65..35763dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -215,7 +215,10 @@
             }
         }
 
-        if (mStatusBarStateController.isDozing()) {
+        // The shelf will be hidden when dozing with a custom clock, we must show notification
+        // icons in this occasion.
+        if (mStatusBarStateController.isDozing()
+                && mStatusBarComponent.getPanel().hasCustomClock()) {
             state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
             state &= ~DISABLE_NOTIFICATION_ICONS;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 280dda0..577e8d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -84,6 +84,14 @@
         public void onCancelled() {
             pulseFinished();
         }
+
+        /**
+         * Whether to fade out wallpaper.
+         */
+        @Override
+        public  boolean isFadeOutWallpaper() {
+            return mPulseReason == DozeLog.PULSE_REASON_DOCKING;
+        }
     };
 
     public DozeScrimController(DozeParameters dozeParameters) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 0fada66..7f75223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -58,7 +58,7 @@
  */
 public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
         ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
-        OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener {
+        OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener, StateListener {
     private static final String TAG = "HeadsUpManagerPhone";
 
     private final View mStatusBarWindowView;
@@ -83,7 +83,6 @@
     private boolean mIsObserving;
     private int mStatusBarState;
 
-    private final StateListener mStateListener = this::setStatusBarState;
     private AnimationStateHandler mAnimationStateHandler;
     private BubbleController mBubbleController = Dependency.get(BubbleController.class);
 
@@ -129,7 +128,7 @@
                 updateTouchableRegionListener();
             }
         });
-        Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).addCallback(this);
         mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
             if (!hasBubbles) {
                 mBubbleGoingAway = true;
@@ -143,7 +142,7 @@
     }
 
     public void destroy() {
-        Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).removeCallback(this);
     }
 
     private void initResources() {
@@ -225,11 +224,9 @@
         }
     }
 
-    /**
-     * Set the current state of the statusbar.
-     */
-    private void setStatusBarState(int statusBarState) {
-        mStatusBarState = statusBarState;
+    @Override
+    public void onStateChanged(int newState) {
+        mStatusBarState = newState;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
new file mode 100644
index 0000000..ebcd39b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.recents.OverviewProxyService;
+
+/**
+ * Assistant is triggered with this action
+ */
+public class NavigationAssistantAction extends NavigationGestureAction {
+    private static final String TAG = "NavigationAssistantActions";
+
+    private final AssistManager mAssistManager;
+
+    public NavigationAssistantAction(@NonNull NavigationBarView navigationBarView,
+            @NonNull OverviewProxyService service, AssistManager assistManager) {
+        super(navigationBarView, service);
+        mAssistManager = assistManager;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+    @Override
+    public void onGestureStart(MotionEvent event) {
+        mAssistManager.startAssist(new Bundle());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index 9c8b1b1..93605ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -67,7 +67,7 @@
 
     @Override
     public boolean isEnabled() {
-        return !getGlobalBoolean(NavigationPrototypeController.NAVBAR_EXPERIMENTS_DISABLED);
+        return true;
     }
 
     @Override
@@ -102,8 +102,7 @@
     }
 
     private boolean shouldExecuteBackOnUp() {
-        return !getGlobalBoolean(NavigationPrototypeController.NAVBAR_EXPERIMENTS_DISABLED)
-                && getGlobalBoolean(BACK_AFTER_END_PROP);
+        return getGlobalBoolean(BACK_AFTER_END_PROP);
     }
 
     private void sendEvent(int action, int code) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 6d97d67..d3c6a1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -269,7 +269,7 @@
             mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
         }
 
-        mNavigationBarView.setComponents(mStatusBar.getPanel());
+        mNavigationBarView.setComponents(mStatusBar.getPanel(), mAssistManager);
         mNavigationBarView.setDisabledFlags(mDisabledFlags1);
         mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
         mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
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 2fc7b78..8bf1c58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -69,6 +69,7 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.assist.AssistManager;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.statusbar.phone.NavGesture;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
@@ -156,6 +157,7 @@
     private QuickStepAction mQuickStepAction;
     private NavigationBackAction mBackAction;
     private QuickSwitchAction mQuickSwitchAction;
+    private NavigationAssistantAction mAssistantAction;
 
     /**
      * Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -366,8 +368,12 @@
         return mBarTransitions.getLightTransitionsController();
     }
 
-    public void setComponents(NotificationPanelView panel) {
+    public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
         mPanelView = panel;
+        if (mAssistantAction == null) {
+            mAssistantAction = new NavigationAssistantAction(this, mOverviewProxyService,
+                    assistManager);
+        }
         if (mGestureHelper instanceof QuickStepController) {
             ((QuickStepController) mGestureHelper).setComponents(this);
             updateNavigationGestures();
@@ -398,6 +404,10 @@
                 return mBackAction;
             case NavigationPrototypeController.ACTION_QUICKSWITCH:
                 return mQuickSwitchAction;
+            case NavigationPrototypeController.ACTION_ASSISTANT:
+                return mAssistantAction;
+            case NavigationPrototypeController.ACTION_NOTHING:
+                return null;
             default:
                 return defaultAction;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
index 8c57fc3..a5d9382 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
@@ -24,6 +24,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.provider.Settings;
 import android.view.MotionEvent;
 
 import com.android.systemui.recents.OverviewProxyService;
@@ -32,6 +33,9 @@
  * A gesture action that would be triggered and reassigned by {@link QuickStepController}
  */
 public abstract class NavigationGestureAction {
+    private static final String ENABLE_TASK_STABILIZER_FLAG = "ENABLE_TASK_STABILIZER";
+
+    static private boolean sLastTaskStabilizationFlag;
 
     protected final NavigationBarView mNavigationBarView;
     protected final OverviewProxyService mProxySender;
@@ -45,6 +49,9 @@
             @NonNull OverviewProxyService service) {
         mNavigationBarView = navigationBarView;
         mProxySender = service;
+        sLastTaskStabilizationFlag = Settings.Global.getInt(
+                mNavigationBarView.getContext().getContentResolver(),
+                ENABLE_TASK_STABILIZER_FLAG, 0) != 0;
     }
 
     /**
@@ -74,6 +81,15 @@
      */
     public void startGesture(MotionEvent event) {
         mIsActive = true;
+
+        // Tell launcher that this action requires a stable task list or not
+        boolean flag = requiresStableTaskList();
+        if (flag != sLastTaskStabilizationFlag) {
+            Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
+                    ENABLE_TASK_STABILIZER_FLAG, flag ? 1 : 0);
+            sLastTaskStabilizationFlag = flag;
+        }
+
         onGestureStart(event);
     }
 
@@ -146,6 +162,13 @@
      */
     public abstract boolean isEnabled();
 
+    /**
+     * @return action requires a stable task list from launcher
+     */
+    protected boolean requiresStableTaskList() {
+        return false;
+    }
+
     protected void onDarkIntensityChange(float intensity) {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index fb6254b..a09e585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -22,7 +22,6 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -36,18 +35,20 @@
     private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
     private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
 
-    static final String NAVBAR_EXPERIMENTS_DISABLED = "navbarexperiments_disabled";
     private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
     public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK})
+    @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
+            ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT})
     @interface GestureAction {}
     static final int ACTION_DEFAULT = 0;
     static final int ACTION_QUICKSTEP = 1;
     static final int ACTION_QUICKSCRUB = 2;
     static final int ACTION_BACK = 3;
     static final int ACTION_QUICKSWITCH = 4;
+    static final int ACTION_NOTHING = 5;
+    static final int ACTION_ASSISTANT = 6;
 
     private OnPrototypeChangedListener mListener;
 
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 1fb5484..077fcda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -23,6 +23,7 @@
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -36,13 +37,15 @@
  * A controller for the space in the status bar to the left of the system icons. This area is
  * normally reserved for notifications.
  */
-public class NotificationIconAreaController implements DarkReceiver {
+public class NotificationIconAreaController implements DarkReceiver,
+        StatusBarStateController.StateListener {
 
     public static final String LOW_PRIORITY = "low_priority";
 
     private final ContrastColorUtil mContrastColorUtil;
     private final NotificationEntryManager mEntryManager;
     private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
+    private final StatusBarStateController mStatusBarStateController;
     private final TunerService.Tunable mTunable = new TunerService.Tunable() {
         @Override
         public void onTuningChanged(String key, String newValue) {
@@ -86,11 +89,14 @@
     private final ViewClippingUtil.ClippingParameters mClippingParameters =
             view -> view instanceof StatusBarWindowView;
 
-    public NotificationIconAreaController(Context context, StatusBar statusBar) {
+    public NotificationIconAreaController(Context context, StatusBar statusBar,
+            StatusBarStateController statusBarStateController) {
         mStatusBar = statusBar;
         mContrastColorUtil = ContrastColorUtil.getInstance(context);
         mContext = context;
         mEntryManager = Dependency.get(NotificationEntryManager.class);
+        mStatusBarStateController = statusBarStateController;
+        mStatusBarStateController.addCallback(this);
 
         Dependency.get(TunerService.class).addTunable(mTunable, LOW_PRIORITY);
 
@@ -373,24 +379,6 @@
         v.setDecorColor(mIconTint);
     }
 
-    /**
-     * Dark amount, from 0 to 1, representing being awake or in AOD.
-     */
-    public void setDarkAmount(float darkAmount) {
-        mDarkAmount = darkAmount;
-        if (darkAmount == 0 || darkAmount == 1) {
-            ViewClippingUtil.setClippingDeactivated(mNotificationIcons, darkAmount != 0,
-                    mClippingParameters);
-        }
-        dozeTimeTick();
-
-        boolean fullyDark = darkAmount == 1f;
-        if (mFullyDark != fullyDark) {
-            mFullyDark = fullyDark;
-            updateShelfIcons();
-        }
-    }
-
     public void setDark(boolean dark) {
         mNotificationIcons.setDark(dark, false, 0);
         mShelfIcons.setDark(dark, false, 0);
@@ -408,10 +396,45 @@
      * Moves icons whenever the device wakes up in AOD, to avoid burn in.
      */
     public void dozeTimeTick() {
+        if (mNotificationIcons.getVisibility() != View.VISIBLE) {
+            return;
+        }
+
+        if (mDarkAmount == 0 && !mStatusBarStateController.isDozing()) {
+            mNotificationIcons.setTranslationX(0);
+            mNotificationIcons.setTranslationY(0);
+            return;
+        }
+
         int yOffset = (mKeyguardStatusBarHeight - getHeight()) / 2;
         int translationX = getBurnInOffset(mBurnInOffset, true /* xAxis */);
         int translationY = getBurnInOffset(mBurnInOffset, false /* xAxis */) + yOffset;
-        mNotificationIcons.setTranslationX(translationX * mDarkAmount);
-        mNotificationIcons.setTranslationY(translationY * mDarkAmount);
+        mNotificationIcons.setTranslationX(translationX);
+        mNotificationIcons.setTranslationY(translationY);
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        dozeTimeTick();
+    }
+
+    @Override
+    public void onDozeAmountChanged(float linear, float eased) {
+        boolean wasOrIsAwake = mDarkAmount == 0 || linear == 0;
+        boolean wasOrIsDozing = mDarkAmount == 1 || linear == 1;
+        mDarkAmount = linear;
+        if (wasOrIsAwake) {
+            ViewClippingUtil.setClippingDeactivated(mNotificationIcons, mDarkAmount != 0,
+                    mClippingParameters);
+        }
+        if (wasOrIsAwake || wasOrIsDozing) {
+            dozeTimeTick();
+        }
+
+        boolean fullyDark = mDarkAmount == 1f;
+        if (mFullyDark != fullyDark) {
+            mFullyDark = fullyDark;
+            updateShelfIcons();
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 964b2210..009afca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -128,6 +128,7 @@
         }
     }.setDuration(CONTENT_FADE_DURATION);
 
+    private static final int MAX_VISIBLE_ICONS_WHEN_DARK = 5;
     public static final int MAX_STATIC_ICONS = 4;
     private static final int MAX_DOTS = 1;
 
@@ -371,7 +372,8 @@
         float translationX = getActualPaddingStart();
         int firstOverflowIndex = -1;
         int childCount = getChildCount();
-        int maxVisibleIcons = mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
+        int maxVisibleIcons = mDark ? MAX_VISIBLE_ICONS_WHEN_DARK :
+                mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
         float layoutEnd = getLayoutEnd();
         float overflowStart = getMaxOverflowStart();
         mVisualOverflowStart = 0;
@@ -387,6 +389,9 @@
             boolean forceOverflow = mSpeedBumpIndex != -1 && i >= mSpeedBumpIndex
                     && iconState.iconAppearAmount > 0.0f || i >= maxVisibleIcons;
             boolean noOverflowAfter = i == childCount - 1;
+            float drawingScale = mDark && view instanceof StatusBarIconView
+                    ? ((StatusBarIconView) view).getIconScaleFullyDark()
+                    : 1f;
             if (mOpenedAmount != 0.0f) {
                 noOverflowAfter = noOverflowAfter && !hasAmbient && !forceOverflow;
             }
@@ -402,7 +407,7 @@
                     mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
                 }
             }
-            translationX += iconState.iconAppearAmount * view.getWidth();
+            translationX += iconState.iconAppearAmount * view.getWidth() * drawingScale;
         }
         mNumDots = 0;
         if (firstOverflowIndex != -1) {
@@ -432,6 +437,32 @@
             mFirstVisibleIconState = mIconStates.get(getChildAt(0));
         }
 
+        boolean center = mDark;
+        if (center && translationX < getLayoutEnd()) {
+            float initialTranslation =
+                    mFirstVisibleIconState == null ? 0 : mFirstVisibleIconState.xTranslation;
+
+            float contentWidth = 0;
+            if (mLastVisibleIconState != null) {
+                contentWidth = mLastVisibleIconState.xTranslation + mIconSize;
+                contentWidth = Math.min(getWidth(), contentWidth) - initialTranslation;
+            }
+            float availableSpace = getLayoutEnd() - getActualPaddingStart();
+            float delta = (availableSpace - contentWidth) / 2;
+
+            if (firstOverflowIndex != -1) {
+                // If we have an overflow, only count those half for centering because the dots
+                // don't have a lot of visual weight.
+                float deltaIgnoringOverflow = (getLayoutEnd() - mVisualOverflowStart) / 2;
+                delta = (deltaIgnoringOverflow + delta) / 2;
+            }
+            for (int i = 0; i < childCount; i++) {
+                View view = getChildAt(i);
+                IconState iconState = mIconStates.get(view);
+                iconState.xTranslation += delta;
+            }
+        }
+
         if (isLayoutRtl()) {
             for (int i = 0; i < childCount; i++) {
                 View view = getChildAt(i);
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 d873b0c..31310f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -50,6 +50,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardClockSwitch;
@@ -142,7 +143,8 @@
     private KeyguardStatusBarView mKeyguardStatusBar;
     private QS mQs;
     private FrameLayout mQsFrame;
-    private KeyguardStatusView mKeyguardStatusView;
+    @VisibleForTesting
+    protected KeyguardStatusView mKeyguardStatusView;
     private View mQsNavbarScrim;
     protected NotificationsQuickSettingsContainer mNotificationContainerParent;
     protected NotificationStackScrollLayout mNotificationStackScroller;
@@ -327,6 +329,13 @@
         mDisplayId = context.getDisplayId();
     }
 
+    /**
+     * Returns if there's a custom clock being presented.
+     */
+    public boolean hasCustomClock() {
+        return mKeyguardStatusView.hasCustomClock();
+    }
+
     private void setStatusBar(StatusBar bar) {
         mStatusBar = bar;
         mKeyguardBottomArea.setStatusBar(mStatusBar);
@@ -956,7 +965,7 @@
             handled = true;
         }
         handled |= super.onTouchEvent(event);
-        return mDozing ? handled : true;
+        return !mDozing || mPulsing || handled;
     }
 
     private boolean handleQsTouch(MotionEvent event) {
@@ -1233,7 +1242,7 @@
             updateDozingVisibilities(false /* animate */);
         }
 
-        resetVerticalPanelPosition();
+        resetHorizontalPanelPosition();
         updateQsState();
     }
 
@@ -2043,7 +2052,7 @@
         super.onConfigurationChanged(newConfig);
         mAffordanceHelper.onConfigurationChanged();
         if (newConfig.orientation != mLastOrientation) {
-            resetVerticalPanelPosition();
+            resetHorizontalPanelPosition();
         }
         mLastOrientation = newConfig.orientation;
     }
@@ -2529,7 +2538,7 @@
     @Override
     protected void onClosingFinished() {
         super.onClosingFinished();
-        resetVerticalPanelPosition();
+        resetHorizontalPanelPosition();
         setClosingWithAlphaFadeout(false);
     }
 
@@ -2546,7 +2555,7 @@
      */
     protected void updateVerticalPanelPosition(float x) {
         if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
-            resetVerticalPanelPosition();
+            resetHorizontalPanelPosition();
             return;
         }
         float leftMost = mPositionMinSideMargin + mNotificationStackScroller.getWidth() / 2;
@@ -2556,16 +2565,17 @@
             x = getWidth() / 2;
         }
         x = Math.min(rightMost, Math.max(leftMost, x));
-        setVerticalPanelTranslation(x -
-                (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2));
+        float center =
+                mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2;
+        setHorizontalPanelTranslation(x - center);
     }
 
-    private void resetVerticalPanelPosition() {
-        setVerticalPanelTranslation(0f);
+    private void resetHorizontalPanelPosition() {
+        setHorizontalPanelTranslation(0f);
     }
 
-    protected void setVerticalPanelTranslation(float translation) {
-        mNotificationStackScroller.setVerticalPanelTranslation(translation);
+    protected void setHorizontalPanelTranslation(float translation) {
+        mNotificationStackScroller.setHorizontalPanelTranslation(translation);
         mQsFrame.setTranslationX(translation);
         int size = mVerticalTranslationListener.size();
         for (int i = 0; i < size; i++) {
@@ -2773,6 +2783,9 @@
         if (dozing == mDozing) return;
         mDozing = dozing;
         mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
+        if (mDozing) {
+            mNotificationStackScroller.setShowDarkShelf(!hasCustomClock());
+        }
 
         if (mBarState == StatusBarState.KEYGUARD
                 || mBarState == StatusBarState.SHADE_LOCKED) {
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 021b430..f17145d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -142,8 +142,8 @@
     private boolean mIgnoreXTouchSlop;
     private boolean mExpandLatencyTracking;
     protected final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
-    protected final StatusBarStateController
-            mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+    protected final StatusBarStateController mStatusBarStateController =
+            Dependency.get(StatusBarStateController.class);
 
     protected void onExpandingFinished() {
         mBar.onExpandingFinished();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
index b18b79e..1999f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
@@ -47,6 +47,10 @@
         return mNavigationBarView.isQuickStepSwipeUpEnabled();
     }
 
+    protected boolean requiresStableTaskList() {
+        return true;
+    }
+
     @Override
     public void onGestureStart(MotionEvent event) {
         try {
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 e25c829..853d7ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -275,9 +275,12 @@
             holdWakeLock();
         }
 
-        // AOD wallpapers should fade away after a while
-        if (mWallpaperSupportsAmbientMode && mDozeParameters.getAlwaysOn()
-                && mState == ScrimState.AOD) {
+        // AOD wallpapers should fade away after a while.
+        // Docking pulses may take a long time, wallpapers should also fade away after a while.
+        if (mWallpaperSupportsAmbientMode && (
+                mDozeParameters.getAlwaysOn() && mState == ScrimState.AOD
+                        || mState == ScrimState.PULSING && mCallback != null
+                        && mCallback.isFadeOutWallpaper())) {
             if (!mWallpaperVisibilityTimedOut) {
                 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
                         AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
@@ -329,7 +332,7 @@
 
     @VisibleForTesting
     protected void onHideWallpaperTimeout() {
-        if (mState != ScrimState.AOD) {
+        if (mState != ScrimState.AOD && mState != ScrimState.PULSING) {
             return;
         }
 
@@ -364,7 +367,7 @@
             mExpansionFraction = fraction;
 
             final boolean keyguardOrUnlocked = mState == ScrimState.UNLOCKED
-                    || mState == ScrimState.KEYGUARD;
+                    || mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING;
             if (!keyguardOrUnlocked || !mExpansionAffectsAlpha) {
                 return;
             }
@@ -409,7 +412,7 @@
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
             mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
             mCurrentInFrontAlpha = 0;
-        } else if (mState == ScrimState.KEYGUARD) {
+        } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING) {
             // Either darken of make the scrim transparent when you
             // pull down the shade
             float interpolatedFract = getInterpolatedFraction();
@@ -504,7 +507,8 @@
 
         // We want to override the back scrim opacity for the AOD state
         // when it's time to fade the wallpaper away.
-        boolean aodWallpaperTimeout = mState == ScrimState.AOD && mWallpaperVisibilityTimedOut;
+        boolean aodWallpaperTimeout = (mState == ScrimState.AOD || mState == ScrimState.PULSING)
+                && mWallpaperVisibilityTimedOut;
         // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
         boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
                 && mKeyguardOccluded;
@@ -562,8 +566,8 @@
         if (alpha == 0f) {
             scrim.setClickable(false);
         } else {
-            // Eat touch events (unless dozing or pulsing).
-            scrim.setClickable(mState != ScrimState.AOD && mState != ScrimState.PULSING);
+            // Eat touch events (unless dozing).
+            scrim.setClickable(mState != ScrimState.AOD);
         }
         updateScrim(scrim, alpha);
     }
@@ -917,6 +921,9 @@
         }
         default void onCancelled() {
         }
+        default boolean isFadeOutWallpaper() {
+            return false;
+        }
     }
 
     /**
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 fb3c4aa..72519ba3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -219,6 +219,14 @@
     public void prepare(ScrimState previousState) {
     }
 
+    /**
+     * Check if lockscreen wallpaper or music album art exists.
+     * @return true if lockscreen wallpaper or music album art exists.
+     */
+    public boolean hasBackdrop() {
+        return mHasBackdrop;
+    }
+
     public int getIndex() {
         return mIndex;
     }
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 6d78f72..3f93192 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -70,6 +70,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -98,6 +99,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
@@ -478,8 +480,13 @@
             WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
             final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
+            final boolean aodImageWallpaperEnabled = FeatureFlagUtils.isEnabled(mContext,
+                    FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+            updateAodMaskVisibility(deviceSupportsAodWallpaper && aodImageWallpaperEnabled);
+            // If WallpaperInfo is null, it must be ImageWallpaper.
             final boolean supportsAmbientMode = deviceSupportsAodWallpaper
-                    && info != null && info.supportsAmbientMode();
+                    && (info == null && aodImageWallpaperEnabled
+                        || info != null && info.supportsAmbientMode());
 
             mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
             mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
@@ -581,6 +588,7 @@
     protected NotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
     private boolean mPulsing;
+    private ContentObserver mFeatureFlagObserver;
 
     @Override
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
@@ -697,6 +705,9 @@
         mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
                 wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
         mWallpaperChangedReceiver.onReceive(mContext, null);
+        mFeatureFlagObserver = new FeatureFlagObserver(
+                FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED /* feature */,
+                () -> mWallpaperChangedReceiver.onReceive(mContext, null) /* callback */);
 
         // Set up the initial notification state. This needs to happen before CommandQueue.disable()
         setUpPresenter();
@@ -789,7 +800,7 @@
         mNotificationLogger.setUpWithContainer(notifListContainer);
 
         mNotificationIconAreaController = SystemUIFactory.getInstance()
-                .createNotificationIconAreaController(context, this);
+                .createNotificationIconAreaController(context, this, mStatusBarStateController);
         inflateShelf();
         mNotificationIconAreaController.setupShelf(mNotificationShelf);
 
@@ -3573,10 +3584,7 @@
             mVisualStabilityManager.setScreenOn(false);
             updateVisibleToUser();
 
-            // We need to disable touch events because these might
-            // collapse the panel after we expanded it, and thus we would end up with a blank
-            // Keyguard.
-            mNotificationPanel.setTouchAndAnimationDisabled(true);
+            updateNotificationPanelTouchState();
             mStatusBarWindow.cancelCurrentTouch();
             if (mLaunchCameraOnFinishedGoingToSleep) {
                 mLaunchCameraOnFinishedGoingToSleep = false;
@@ -3599,13 +3607,22 @@
             mDeviceInteractive = true;
             mAmbientPulseManager.releaseAllImmediately();
             mVisualStabilityManager.setScreenOn(true);
-            mNotificationPanel.setTouchAndAnimationDisabled(false);
+            updateNotificationPanelTouchState();
             updateVisibleToUser();
             updateIsKeyguard();
             mDozeServiceHost.stopDozing();
         }
     };
 
+    /**
+     * We need to disable touch events because these might
+     * collapse the panel after we expanded it, and thus we would end up with a blank
+     * Keyguard.
+     */
+    private void updateNotificationPanelTouchState() {
+        mNotificationPanel.setTouchAndAnimationDisabled(!mDeviceInteractive && !mPulsing);
+    }
+
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
         @Override
         public void onScreenTurningOn() {
@@ -3871,17 +3888,15 @@
                 @Override
                 public void onPulseStarted() {
                     callback.onPulseStarted();
-                    if (mAmbientPulseManager.hasNotifications()) {
-                        // Only pulse the stack scroller if there's actually something to show.
-                        // Otherwise just show the always-on screen.
-                        setPulsing(true);
-                    }
+                    updateNotificationPanelTouchState();
+                    setPulsing(true);
                 }
 
                 @Override
                 public void onPulseFinished() {
                     mPulsing = false;
                     callback.onPulseFinished();
+                    updateNotificationPanelTouchState();
                     setPulsing(false);
                 }
 
@@ -4411,4 +4426,33 @@
     public @TransitionMode int getStatusBarMode() {
         return mStatusBarMode;
     }
+
+    private void updateAodMaskVisibility(boolean supportsAodWallpaper) {
+        View mask = mStatusBarWindow.findViewById(R.id.aod_mask);
+        if (mask != null) {
+            mask.setVisibility(supportsAodWallpaper ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+
+    private final class FeatureFlagObserver extends ContentObserver {
+        private final Runnable mCallback;
+
+        FeatureFlagObserver(String feature, Runnable callback) {
+            this(null, feature, callback);
+        }
+
+        private FeatureFlagObserver(Handler handler, String feature, Runnable callback) {
+            super(handler);
+            mCallback = callback;
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Global.getUriFor(feature), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            if (mCallback != null) {
+                mStatusBarWindow.post(mCallback);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index db7589d..f846036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -36,7 +36,6 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -61,7 +60,6 @@
 
     private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
     private final ArraySet<String> mIconBlacklist = new ArraySet<>();
-    private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
 
     // Points to light or dark context depending on the... context?
     private Context mContext;
@@ -147,7 +145,6 @@
         int viewIndex = getViewIndex(index, holder.getTag());
         boolean blocked = mIconBlacklist.contains(slot);
 
-        mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
         mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
     }
 
@@ -281,8 +278,6 @@
             return;
         }
 
-        mIconLogger.onIconHidden(slotName);
-
         int slotIndex = getSlotIndex(slotName);
         List<StatusBarIconHolder> iconsToRemove = slot.getHolderListInViewOrder();
         for (StatusBarIconHolder holder : iconsToRemove) {
@@ -297,7 +292,6 @@
         if (getIcon(index, tag) == null) {
             return;
         }
-        mIconLogger.onIconHidden(getSlotName(index));
         super.removeIcon(index, tag);
         int viewIndex = getViewIndex(index, 0);
         mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
@@ -305,7 +299,6 @@
 
     private void handleSet(int index, StatusBarIconHolder holder) {
         int viewIndex = getViewIndex(index, holder.getTag());
-        mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
         mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
     }
 
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 0f8970f..bb23608 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -187,7 +187,7 @@
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
         } else if (bouncerNeedsScrimming()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
-        } else if (mShowing && !mDozing) {
+        } else if (mShowing) {
             if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) {
                 mBouncer.setExpansion(expansion);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 3ddfc0c..8d58410 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -53,7 +53,8 @@
 /**
  */
 @Singleton
-public class StatusBarRemoteInputCallback implements Callback, Callbacks {
+public class StatusBarRemoteInputCallback implements Callback, Callbacks,
+        StatusBarStateController.StateListener {
 
     private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
     private final StatusBarStateController mStatusBarStateController
@@ -63,7 +64,6 @@
     private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
     private final Context mContext;
     private View mPendingWorkRemoteInputView;
-    private final StatusBarStateController.StateListener mStateListener = this::setStatusBarState;
     private View mPendingRemoteInputView;
     private final ShadeController mShadeController = Dependency.get(ShadeController.class);
     private KeyguardManager mKeyguardManager;
@@ -78,13 +78,14 @@
         mContext = context;
         mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
                 new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
-        mStatusBarStateController.addCallback(mStateListener);
+        mStatusBarStateController.addCallback(this);
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
         mCommandQueue = getComponent(context, CommandQueue.class);
         mCommandQueue.addCallback(this);
     }
 
-    private void setStatusBarState(int state) {
+    @Override
+    public void onStateChanged(int state) {
         if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
             if (!mStatusBarStateController.isKeyguardRequested()) {
                 if (mPendingRemoteInputView != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 53e461d..8b25c34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -339,7 +339,7 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
-        if (mService.isDozing() && !stackScrollLayout.hasPulsingNotifications()) {
+        if (mService.isDozing() && !mService.isPulsing()) {
             // Capture all touch events in always-on.
             return true;
         }
@@ -347,8 +347,7 @@
         if (mNotificationPanel.isFullyExpanded()
                 && stackScrollLayout.getVisibility() == View.VISIBLE
                 && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
-                && !mService.isBouncerShowing()
-                && !mService.isDozing()) {
+                && !mService.isBouncerShowing()) {
             intercept = mDragDownHelper.onInterceptTouchEvent(ev);
         }
         if (!intercept) {
@@ -369,7 +368,7 @@
         boolean handled = false;
         if (mService.isDozing()) {
             mDoubleTapHelper.onTouchEvent(ev);
-            handled = true;
+            handled = !mService.isPulsing();
         }
         if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled)
                 || mDragDownHelper.isDraggingDown()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index f65f826..5e94152 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -48,18 +48,36 @@
     }
 
     /**
-     * A listener that will be notified whenever a change in battery level or power save mode
-     * has occurred.
+     * A listener that will be notified whenever a change in battery level or power save mode has
+     * occurred.
      */
     interface BatteryStateChangeCallback {
-        default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {}
-        default void onPowerSaveChanged(boolean isPowerSave) {}
+
+        default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        }
+
+        default void onPowerSaveChanged(boolean isPowerSave) {
+        }
     }
 
     /**
-     * If available, get the estimated battery time remaining as a string
+     * If available, get the estimated battery time remaining as a string.
+     *
+     * @param completion A lambda that will be called with the result of fetching the estimate. The
+     * first time this method is called may need to be dispatched to a background thread. The
+     * completion is called on the main thread
      */
-    default String getEstimatedTimeRemainingString() {
-        return null;
+    default void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {}
+
+    /**
+     * Callback called when the estimated time remaining text is fetched.
+     */
+    public interface EstimateFetchCompletion {
+
+        /**
+         * The callback
+         * @param estimate the estimate
+         */
+        void onBatteryRemainingEstimateRetrieved(String estimate);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 6190c8f..af3c96f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -27,9 +27,12 @@
 import android.os.PowerSaveState;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
 import com.android.settingslib.utils.PowerUtil;
+import com.android.systemui.Dependency;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.Estimate;
 
@@ -56,6 +59,7 @@
 
     private final EnhancedEstimates mEstimates;
     private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
+    private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
     private final PowerManager mPowerManager;
     private final Handler mHandler;
     private final Context mContext;
@@ -70,6 +74,7 @@
     private boolean mHasReceivedBattery = false;
     private Estimate mEstimate;
     private long mLastEstimateTimestamp = -1;
+    private boolean mFetchingEstimate = false;
 
     @Inject
     public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates) {
@@ -197,20 +202,61 @@
     }
 
     @Override
-    public String getEstimatedTimeRemainingString() {
-        if (mEstimate == null
-                || System.currentTimeMillis() > mLastEstimateTimestamp + UPDATE_GRANULARITY_MSEC) {
-            updateEstimate();
+    public void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {
+        if (mEstimate != null
+                && mLastEstimateTimestamp > System.currentTimeMillis() - UPDATE_GRANULARITY_MSEC) {
+            String percentage = generateTimeRemainingString();
+            completion.onBatteryRemainingEstimateRetrieved(percentage);
+            return;
         }
-        // Estimates may not exist yet even if we've checked
+
+        // Need to fetch or refresh the estimate, but it may involve binder calls so offload the
+        // work
+        synchronized (mFetchCallbacks) {
+            mFetchCallbacks.add(completion);
+        }
+        updateEstimateInBackground();
+    }
+
+    @Nullable
+    private String generateTimeRemainingString() {
         if (mEstimate == null) {
             return null;
         }
-        final String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
+
+        String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
         return PowerUtil.getBatteryRemainingShortStringFormatted(
                 mContext, mEstimate.estimateMillis);
     }
 
+    private void updateEstimateInBackground() {
+        if (mFetchingEstimate) {
+            // Already dispatched a fetch. It will notify all listeners when finished
+            return;
+        }
+
+        mFetchingEstimate = true;
+        Dependency.get(Dependency.BG_HANDLER).post(() -> {
+            mEstimate = mEstimates.getEstimate();
+            mLastEstimateTimestamp = System.currentTimeMillis();
+            mFetchingEstimate = false;
+
+            Dependency.get(Dependency.MAIN_HANDLER).post(this::notifyEstimateFetchCallbacks);
+        });
+    }
+
+    private void notifyEstimateFetchCallbacks() {
+        String estimate = generateTimeRemainingString();
+
+        synchronized (mFetchCallbacks) {
+            for (EstimateFetchCompletion completion : mFetchCallbacks) {
+                completion.onBatteryRemainingEstimateRetrieved(estimate);
+            }
+
+            mFetchCallbacks.clear();
+        }
+    }
+
     private void updateEstimate() {
         mEstimate = mEstimates.getEstimate();
         mLastEstimateTimestamp = System.currentTimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index de7ef3b..4299af7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -274,7 +274,6 @@
 
     private void updateClockVisibility() {
         boolean visible = shouldBeVisible();
-        Dependency.get(IconLogger.class).onIconVisibility("clock", visible);
         int visibility = visible ? View.VISIBLE : View.GONE;
         super.setVisibility(visibility);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java
deleted file mode 100644
index 710e1df..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java
+++ /dev/null
@@ -1,29 +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.statusbar.policy;
-
-public interface IconLogger {
-
-    void onIconShown(String tag);
-    void onIconHidden(String tag);
-
-    default void onIconVisibility(String tag, boolean visible) {
-        if (visible) {
-            onIconShown(tag);
-        } else {
-            onIconHidden(tag);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java
deleted file mode 100644
index ba6369e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java
+++ /dev/null
@@ -1,115 +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.statusbar.policy;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.STATUS_BAR_ICONS_CHANGED;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
-
-import android.content.Context;
-import android.metrics.LogMaker;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.ArraySet;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.logging.MetricsLogger;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-public class IconLoggerImpl implements IconLogger {
-
-    // Minimum ms between log statements.
-    // NonFinalForTesting
-    @VisibleForTesting
-    protected static long MIN_LOG_INTERVAL = 1000;
-
-    private final Context mContext;
-    private final Handler mHandler;
-    private final MetricsLogger mLogger;
-    private final ArraySet<String> mIcons = new ArraySet<>();
-    private final List<String> mIconIndex;
-    private long mLastLog = System.currentTimeMillis();
-
-    @Inject
-    public IconLoggerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper,
-            MetricsLogger logger) {
-        mContext = context;
-        mHandler = new Handler(bgLooper);
-        mLogger = logger;
-        String[] icons = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_statusBarIcons);
-        mIconIndex = Arrays.asList(icons);
-        doLog();
-    }
-
-    @Override
-    public void onIconShown(String tag) {
-        synchronized (mIcons) {
-            if (mIcons.contains(tag)) return;
-            mIcons.add(tag);
-        }
-        if (!mHandler.hasCallbacks(mLog)) {
-            mHandler.postDelayed(mLog, MIN_LOG_INTERVAL);
-        }
-    }
-
-    @Override
-    public void onIconHidden(String tag) {
-        synchronized (mIcons) {
-            if (!mIcons.contains(tag)) return;
-            mIcons.remove(tag);
-        }
-        if (!mHandler.hasCallbacks(mLog)) {
-            mHandler.postDelayed(mLog, MIN_LOG_INTERVAL);
-        }
-    }
-
-    private void doLog() {
-        long time = System.currentTimeMillis();
-        long timeSinceLastLog = time - mLastLog;
-        mLastLog = time;
-
-        ArraySet<String> icons;
-        synchronized (mIcons) {
-            icons = new ArraySet<>(mIcons);
-        }
-        mLogger.write(new LogMaker(STATUS_BAR_ICONS_CHANGED)
-                .setType(TYPE_ACTION)
-                .setLatency(timeSinceLastLog)
-                .addTaggedData(FIELD_NUM_STATUS_ICONS, icons.size())
-                .addTaggedData(FIELD_STATUS_ICONS, getBitField(icons)));
-    }
-
-    private int getBitField(ArraySet<String> icons) {
-        int iconsVisible = 0;
-        for (String icon : icons) {
-            int index = mIconIndex.indexOf(icon);
-            if (index >= 0) {
-                iconsVisible |= (1 << index);
-            }
-        }
-        return iconsVisible;
-    }
-
-    private final Runnable mLog = this::doLog;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index 0c63e29..3bd0d45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -45,16 +45,19 @@
             "max_squeeze_remeasure_attempts";
     private static final String KEY_EDIT_CHOICES_BEFORE_SENDING =
             "edit_choices_before_sending";
+    private static final String KEY_SHOW_IN_HEADS_UP = "show_in_heads_up";
 
     private final boolean mDefaultEnabled;
     private final boolean mDefaultRequiresP;
     private final int mDefaultMaxSqueezeRemeasureAttempts;
     private final boolean mDefaultEditChoicesBeforeSending;
+    private final boolean mDefaultShowInHeadsUp;
 
     private boolean mEnabled;
     private boolean mRequiresTargetingP;
     private int mMaxSqueezeRemeasureAttempts;
     private boolean mEditChoicesBeforeSending;
+    private boolean mShowInHeadsUp;
 
     private final Context mContext;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -73,6 +76,8 @@
                 R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts);
         mDefaultEditChoicesBeforeSending = resources.getBoolean(
                 R.bool.config_smart_replies_in_notifications_edit_choices_before_sending);
+        mDefaultShowInHeadsUp = resources.getBoolean(
+                R.bool.config_smart_replies_in_notifications_show_in_heads_up);
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS),
@@ -99,6 +104,7 @@
                     KEY_MAX_SQUEEZE_REMEASURE_ATTEMPTS, mDefaultMaxSqueezeRemeasureAttempts);
             mEditChoicesBeforeSending = mParser.getBoolean(
                     KEY_EDIT_CHOICES_BEFORE_SENDING, mDefaultEditChoicesBeforeSending);
+            mShowInHeadsUp = mParser.getBoolean(KEY_SHOW_IN_HEADS_UP, mDefaultShowInHeadsUp);
         }
     }
 
@@ -142,4 +148,11 @@
                 return mEditChoicesBeforeSending;
         }
     }
+
+    /**
+     * Returns whether smart suggestions should be enabled in heads-up notifications.
+     */
+    public boolean getShowInHeadsUp() {
+        return mShowInHeadsUp;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
new file mode 100644
index 0000000..52cabe2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.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.systemui.wallpaper;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.util.AttributeSet;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.widget.ImageView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.systemui.statusbar.phone.ScrimState;
+
+/**
+ * A view that draws mask upon either image wallpaper or music album art in AOD.
+ */
+public class AodMaskView extends ImageView implements StatusBarStateController.StateListener,
+        ImageWallpaperTransformer.TransformationListener {
+    private static final String TAG = AodMaskView.class.getSimpleName();
+    private static final int TRANSITION_DURATION = 1000;
+
+    private static final AnimatableProperty TRANSITION_PROGRESS = AnimatableProperty.from(
+            "transition_progress",
+            AodMaskView::setTransitionAmount,
+            AodMaskView::getTransitionAmount,
+            R.id.aod_mask_transition_progress_tag,
+            R.id.aod_mask_transition_progress_start_tag,
+            R.id.aod_mask_transition_progress_end_tag
+    );
+
+    private final AnimationProperties mTransitionProperties = new AnimationProperties();
+    private final ImageWallpaperTransformer mTransformer;
+    private final RectF mBounds = new RectF();
+    private boolean mChangingStates;
+    private boolean mNeedMask;
+    private float mTransitionAmount;
+    private final WallpaperManager mWallpaperManager;
+    private final DisplayManager mDisplayManager;
+    private DisplayListener mDisplayListener = new DisplayListener() {
+        @Override
+        public void onDisplayAdded(int displayId) {
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            // We just support DEFAULT_DISPLAY currently.
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                mTransformer.updateDisplayInfo(getDisplayInfo(displayId));
+            }
+        }
+    };
+
+    public AodMaskView(Context context) {
+        this(context, null);
+    }
+
+    public AodMaskView(Context context, AttributeSet attrs) {
+        this(context, attrs, null);
+    }
+
+    @VisibleForTesting
+    public AodMaskView(Context context, AttributeSet attrs, ImageWallpaperTransformer transformer) {
+        super(context, attrs);
+        setClickable(false);
+
+        StatusBarStateController controller = Dependency.get(StatusBarStateController.class);
+        if (controller != null) {
+            controller.addCallback(this);
+        } else {
+            Log.d(TAG, "Can not get StatusBarStateController!");
+        }
+
+        mDisplayManager = (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
+        mDisplayManager.registerDisplayListener(mDisplayListener, null);
+        mWallpaperManager =
+                (WallpaperManager) getContext().getSystemService(Context.WALLPAPER_SERVICE);
+
+        if (transformer == null) {
+            mTransformer = new ImageWallpaperTransformer(this);
+            mTransformer.addFilter(new ScrimFilter());
+            mTransformer.addFilter(new VignetteFilter());
+            mTransformer.updateOffsets();
+            mTransformer.updateDisplayInfo(getDisplayInfo(Display.DEFAULT_DISPLAY));
+
+            mTransitionProperties.setDuration(TRANSITION_DURATION);
+            mTransitionProperties.setAnimationFinishListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mTransformer.setIsTransiting(false);
+                }
+
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mTransformer.setIsTransiting(true);
+                }
+            });
+        } else {
+            // This part should only be hit by test cases.
+            mTransformer = transformer;
+        }
+    }
+
+    private DisplayInfo getDisplayInfo(int displayId) {
+        DisplayInfo displayInfo = new DisplayInfo();
+        mDisplayManager.getDisplay(displayId).getDisplayInfo(displayInfo);
+        return displayInfo;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mBounds.set(0, 0, w, h);
+        mTransformer.updateOffsets();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (mNeedMask) {
+            mTransformer.drawTransformedImage(canvas, null /* target */, null /* src */, mBounds);
+        }
+    }
+
+    private boolean checkIfNeedMask() {
+        // We need mask for ImageWallpaper / LockScreen Wallpaper (Music album art).
+        return mWallpaperManager.getWallpaperInfo() == null || ScrimState.AOD.hasBackdrop();
+    }
+
+    @Override
+    public void onStatePreChange(int oldState, int newState) {
+        mChangingStates = oldState != newState;
+        mNeedMask = checkIfNeedMask();
+    }
+
+    @Override
+    public void onStatePostChange() {
+        mChangingStates = false;
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        if (!mNeedMask) {
+            return;
+        }
+
+        boolean enabled = checkFeatureIsEnabled();
+        mTransformer.updateAmbientModeState(enabled && isDozing);
+
+        if (enabled && !mChangingStates) {
+            setAnimatorProperty(isDozing);
+        } else {
+            invalidate();
+        }
+    }
+
+    private boolean checkFeatureIsEnabled() {
+        return FeatureFlagUtils.isEnabled(
+                getContext(), FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+    }
+
+    @VisibleForTesting
+    void setAnimatorProperty(boolean isDozing) {
+        PropertyAnimator.setProperty(
+                this,
+                TRANSITION_PROGRESS,
+                isDozing ? 1f : 0f /* newEndValue */,
+                mTransitionProperties,
+                true /* animated */);
+    }
+
+    @Override
+    public void onTransformationUpdated() {
+        invalidate();
+    }
+
+    private void setTransitionAmount(float amount) {
+        mTransitionAmount = amount;
+        mTransformer.updateTransitionAmount(amount);
+    }
+
+    private float getTransitionAmount() {
+        return mTransitionAmount;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java
new file mode 100644
index 0000000..d457dac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java
@@ -0,0 +1,81 @@
+/*
+ * 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.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * Abstract filter used by static image wallpaper.
+ */
+abstract class ImageWallpaperFilter {
+    protected static final boolean DEBUG = false;
+
+    private ImageWallpaperTransformer mTransformer;
+
+    /**
+     * Apply this filter to the bitmap before drawing on canvas.
+     * @param c      The canvas that will draw to.
+     * @param bitmap The bitmap to apply this filter.
+     * @param src    The subset of the bitmap to be drawn.
+     * @param dest   The rectangle that the bitmap will be scaled/translated to fit into.
+     */
+    public abstract void apply(@NonNull Canvas c, @Nullable Bitmap bitmap,
+            @Nullable Rect src, @NonNull RectF dest);
+
+    /**
+     * Notifies the occurrence of built-in transition of the animation.
+     * @param animator The animator which was animated.
+     */
+    public abstract void onAnimatorUpdate(ValueAnimator animator);
+
+    /**
+     * Notifies the occurrence of another transition of the animation.
+     * @param amount The transition amount.
+     */
+    public abstract void onTransitionAmountUpdate(float amount);
+
+    /**
+     * To set the associated transformer.
+     * @param transformer The transformer that is associated with this filter.
+     */
+    public void setTransformer(ImageWallpaperTransformer transformer) {
+        if (transformer != null) {
+            mTransformer = transformer;
+        }
+    }
+
+    protected ImageWallpaperTransformer getTransformer() {
+        return mTransformer;
+    }
+
+    /**
+     * Notifies the changing of the offset value of the ImageWallpaper.
+     * @param force True to force re-evaluate offsets.
+     * @param xOffset X offset of the ImageWallpaper in percentage.
+     * @param yOffset Y offset of the ImageWallpaper in percentage.
+     */
+    public void onOffsetsUpdate(boolean force, float xOffset, float yOffset) {
+        // No-op
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java
new file mode 100644
index 0000000..25b0b0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallpaper;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.DisplayInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class is used to manage the filters that will be applied.
+ */
+public class ImageWallpaperTransformer {
+    private static final String TAG = ImageWallpaperTransformer.class.getSimpleName();
+
+    private DisplayInfo mDisplayInfo;
+    private final List<ImageWallpaperFilter> mFilters;
+    private final TransformationListener mListener;
+    private boolean mIsInAmbientMode;
+    private boolean mIsTransiting;
+
+    /**
+     * Constructor.
+     * @param listener A listener to inform you the transformation has updated.
+     */
+    public ImageWallpaperTransformer(TransformationListener listener) {
+        mFilters = new ArrayList<>();
+        mListener = listener;
+    }
+
+    /**
+     * Claim that we want to use the specified filter.
+     * @param filter The filter will be used.
+     */
+    public void addFilter(ImageWallpaperFilter filter) {
+        if (filter != null) {
+            filter.setTransformer(this);
+            mFilters.add(filter);
+        }
+    }
+
+    /**
+     * Check if any transition is running.
+     * @return True if the transition is running, false otherwise.
+     */
+    boolean isTransiting() {
+        return mIsTransiting;
+    }
+
+    /**
+     * Indicate if any transition is running. <br/>
+     * @param isTransiting True if the transition is running.
+     */
+    void setIsTransiting(boolean isTransiting) {
+        mIsTransiting = isTransiting;
+    }
+
+    /**
+     * Check if the device is in ambient mode.
+     * @return True if the device is in ambient mode, false otherwise.
+     */
+    public boolean isInAmbientMode() {
+        return mIsInAmbientMode;
+    }
+
+    /**
+     * Update current state of ambient mode.
+     * @param isInAmbientMode Current ambient mode state.
+     */
+    public void updateAmbientModeState(boolean isInAmbientMode) {
+        mIsInAmbientMode = isInAmbientMode;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        int idx = 0;
+        for (ImageWallpaperFilter filter : mFilters) {
+            sb.append(idx++).append(": ").append(filter.getClass().getSimpleName()).append("\n");
+        }
+        if (sb.length() == 0) {
+            sb.append("No filters applied");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Set a new display info.
+     * @param displayInfo New display info.
+     */
+    public void updateDisplayInfo(DisplayInfo displayInfo) {
+        mDisplayInfo = displayInfo;
+    }
+
+    /**
+     * To get current display info.
+     * @return Current display info.
+     */
+    public DisplayInfo getDisplayInfo() {
+        return mDisplayInfo;
+    }
+
+    /**
+     * Update the offsets with default value.
+     */
+    public void updateOffsets() {
+        this.updateOffsets(true, 0f, .5f);
+    }
+
+    /**
+     * To notify the filters that the offset of the ImageWallpaper changes.
+     * @param force True to force re-evaluate offsets.
+     * @param offsetX X offset of the ImageWallpaper in percentage.
+     * @param offsetY Y offset of the ImageWallpaper in percentage.
+     */
+    public void updateOffsets(boolean force, float offsetX, float offsetY) {
+        mFilters.forEach(filter -> filter.onOffsetsUpdate(force, offsetX, offsetY));
+    }
+
+    /**
+     * Apply all specified filters to the bitmap then draw to the canvas.
+     * @param c      The canvas that will draw to.
+     * @param target The bitmap to apply filters.
+     * @param src    The subset of the bitmap to be drawn
+     * @param dest   The rectangle that the bitmap will be scaled/translated to fit into.
+     */
+    void drawTransformedImage(@NonNull Canvas c, @Nullable Bitmap target,
+            @Nullable Rect src, @NonNull RectF dest) {
+        mFilters.forEach(filter -> filter.apply(c, target, src, dest));
+    }
+
+    /**
+     * Update the transition amount. <br/>
+     * Must invoke this to update transition amount if not running built-in transition.
+     * @param amount The transition amount.
+     */
+    void updateTransitionAmount(float amount) {
+        mFilters.forEach(filter -> filter.onTransitionAmountUpdate(amount));
+        if (mListener != null) {
+            mListener.onTransformationUpdated();
+        }
+    }
+
+    /**
+     * An interface that informs the transformation status.
+     */
+    public interface TransformationListener {
+        /**
+         * Notifies the update of the transformation.
+         */
+        void onTransformationUpdated();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java
new file mode 100644
index 0000000..637e48e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * A filter that implements 70% black scrim effect.
+ */
+public class ScrimFilter extends ImageWallpaperFilter {
+    private static final int MAX_ALPHA = (int) (255 * .7f);
+    private static final int MIN_ALPHA = 0;
+
+    private final Paint mPaint;
+
+    public ScrimFilter() {
+        mPaint = new Paint();
+        mPaint.setColor(Color.BLACK);
+        mPaint.setAlpha(MAX_ALPHA);
+    }
+
+    @Override
+    public void apply(Canvas c, Bitmap bitmap, Rect src, RectF dest) {
+        ImageWallpaperTransformer transformer = getTransformer();
+
+        // If it is not in the transition, we need to set the property according to aod state.
+        if (!transformer.isTransiting()) {
+            mPaint.setAlpha(transformer.isInAmbientMode() ? MAX_ALPHA : MIN_ALPHA);
+        }
+
+        c.drawRect(dest, mPaint);
+    }
+
+    @Override
+    public void onAnimatorUpdate(ValueAnimator animator) {
+        ImageWallpaperTransformer transformer = getTransformer();
+        float fraction = animator.getAnimatedFraction();
+        float factor = transformer.isInAmbientMode() ? fraction : 1f - fraction;
+        mPaint.setAlpha((int) (factor * MAX_ALPHA));
+    }
+
+    @Override
+    public void onTransitionAmountUpdate(float amount) {
+        mPaint.setAlpha((int) (amount * MAX_ALPHA));
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java
new file mode 100644
index 0000000..ad0b98b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java
@@ -0,0 +1,124 @@
+/*
+ * 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.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.util.Log;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A filter that implements vignette effect.
+ */
+public class VignetteFilter extends ImageWallpaperFilter {
+    private static final String TAG = VignetteFilter.class.getSimpleName();
+    private static final int MAX_ALPHA = 255;
+    private static final int MIN_ALPHA = 0;
+
+    private final Paint mPaint;
+    private final Matrix mMatrix;
+    private final Shader mShader;
+
+    private float mXOffset;
+    private float mYOffset;
+    private float mCenterX;
+    private float mCenterY;
+    private float mStretchX;
+    private float mStretchY;
+    private boolean mCalculateOffsetNeeded;
+
+    public VignetteFilter() {
+        mPaint = new Paint();
+        mMatrix = new Matrix();
+        mShader = new RadialGradient(0, 0, 1,
+                Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP);
+    }
+
+    @Override
+    public void apply(Canvas c, Bitmap bitmap, Rect src, RectF dest) {
+        DisplayInfo info = getTransformer().getDisplayInfo();
+
+        if (mCalculateOffsetNeeded) {
+            int lw = info.logicalWidth;
+            int lh = info.logicalHeight;
+            mCenterX = lw / 2 + (dest.width() - lw) * mXOffset;
+            mCenterY = lh / 2 + (dest.height() - lh) * mYOffset;
+            mStretchX = info.logicalWidth / 2;
+            mStretchY = info.logicalHeight / 2;
+            mCalculateOffsetNeeded = false;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "apply: lw=" + info.logicalWidth + ", lh=" + info.logicalHeight
+                    + ", center=(" + mCenterX + "," + mCenterY + ")"
+                    + ", stretch=(" + mStretchX + "," + mStretchY + ")");
+        }
+
+        mMatrix.reset();
+        mMatrix.postTranslate(mCenterX, mCenterY);
+        mMatrix.postScale(mStretchX, mStretchY, mCenterX, mCenterY);
+        mShader.setLocalMatrix(mMatrix);
+        mPaint.setShader(mShader);
+
+        ImageWallpaperTransformer transformer = getTransformer();
+
+        // If it is not in the transition, we need to set the property according to aod state.
+        if (!transformer.isTransiting()) {
+            mPaint.setAlpha(transformer.isInAmbientMode() ? MAX_ALPHA : MIN_ALPHA);
+        }
+
+        c.drawRect(dest, mPaint);
+    }
+
+    @Override
+    public void onAnimatorUpdate(ValueAnimator animator) {
+        ImageWallpaperTransformer transformer = getTransformer();
+        float fraction = animator.getAnimatedFraction();
+        float factor = transformer.isInAmbientMode() ? fraction : 1f - fraction;
+        mPaint.setAlpha((int) (factor * MAX_ALPHA));
+    }
+
+    @Override
+    public void onTransitionAmountUpdate(float amount) {
+        mPaint.setAlpha((int) (amount * MAX_ALPHA));
+    }
+
+    @Override
+    public void onOffsetsUpdate(boolean force, float xOffset, float yOffset) {
+        if (force || mXOffset != xOffset || mYOffset != yOffset) {
+            mXOffset = xOffset;
+            mYOffset = yOffset;
+            mCalculateOffsetNeeded = true;
+        }
+    }
+
+    @VisibleForTesting
+    public PointF getCenterPoint() {
+        return new PointF(mCenterX, mCenterY);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 1844df5..fbc1c20 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -21,7 +21,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -42,19 +41,18 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.function.Consumer;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 // Need to run on the main thread because KeyguardSliceView$Row init checks for
@@ -62,7 +60,6 @@
 // the keyguard_clcok_switch layout is inflated.
 @RunWithLooper(setAsMainLooper = true)
 public class KeyguardClockSwitchTest extends SysuiTestCase {
-    private PluginManager mPluginManager;
     private FrameLayout mClockContainer;
     private StatusBarStateController.StateListener mStateListener;
 
@@ -73,7 +70,6 @@
 
     @Before
     public void setUp() {
-        mPluginManager = mDependency.injectMockDependency(PluginManager.class);
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
         mKeyguardClockSwitch =
                 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
@@ -84,29 +80,12 @@
     }
 
     @Test
-    public void onAttachToWindow_addPluginListener() {
-        mKeyguardClockSwitch.onAttachedToWindow();
-
-        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
-        verify(mPluginManager).addPluginListener(listener.capture(), eq(ClockPlugin.class));
-    }
-
-    @Test
-    public void onDetachToWindow_removePluginListener() {
-        mKeyguardClockSwitch.onDetachedFromWindow();
-
-        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
-        verify(mPluginManager).removePluginListener(listener.capture());
-    }
-
-    @Test
     public void onPluginConnected_showPluginClock() {
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
 
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
 
         verify(mClockView).setVisibility(GONE);
         assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer);
@@ -122,9 +101,8 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getBigClockView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
         // WHEN the plugin is connected
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
         // THEN the big clock container is visible and it is the parent of the
         // big clock view.
         assertThat(bigClockContainer.getVisibility()).isEqualTo(VISIBLE);
@@ -134,8 +112,7 @@
     @Test
     public void onPluginConnected_nullView() {
         ClockPlugin plugin = mock(ClockPlugin.class);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
         verify(mClockView, never()).setVisibility(GONE);
     }
 
@@ -144,27 +121,36 @@
         // GIVEN a plugin has already connected
         ClockPlugin plugin1 = mock(ClockPlugin.class);
         when(plugin1.getView()).thenReturn(new TextClock(getContext()));
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin1, null);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin1);
         // WHEN a second plugin is connected
         ClockPlugin plugin2 = mock(ClockPlugin.class);
         when(plugin2.getView()).thenReturn(new TextClock(getContext()));
-        listener.onPluginConnected(plugin2, null);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin2);
         // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
         assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
         assertThat(plugin1.getView().getParent()).isNull();
     }
 
     @Test
+    public void onPluginConnected_darkAmountInitialized() {
+        // GIVEN that the dark amount has already been set
+        mKeyguardClockSwitch.setDarkAmount(0.5f);
+        // WHEN a plugin is connected
+        ClockPlugin plugin = mock(ClockPlugin.class);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
+        // THEN dark amount should be initalized on the plugin.
+        verify(plugin).setDarkAmount(0.5f);
+    }
+
+    @Test
     public void onPluginDisconnected_showDefaultClock() {
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
         mClockView.setVisibility(GONE);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
 
-        listener.onPluginConnected(plugin, null);
-        listener.onPluginDisconnected(plugin);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(null);
 
         verify(mClockView).setVisibility(VISIBLE);
         assertThat(plugin.getView().getParent()).isNull();
@@ -180,10 +166,9 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getBigClockView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
-        // WHEN the plugin is disconnected
-        listener.onPluginDisconnected(plugin);
+        // WHEN the plugin is connected and then disconnected
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(null);
         // THEN the big lock container is GONE and the big clock view doesn't have
         // a parent.
         assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE);
@@ -193,41 +178,23 @@
     @Test
     public void onPluginDisconnected_nullView() {
         ClockPlugin plugin = mock(ClockPlugin.class);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
-        listener.onPluginDisconnected(plugin);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(null);
         verify(mClockView, never()).setVisibility(GONE);
     }
 
     @Test
-    public void onPluginDisconnected_firstOfTwoDisconnected() {
-        // GIVEN two plugins are connected
-        ClockPlugin plugin1 = mock(ClockPlugin.class);
-        when(plugin1.getView()).thenReturn(new TextClock(getContext()));
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin1, null);
-        ClockPlugin plugin2 = mock(ClockPlugin.class);
-        when(plugin2.getView()).thenReturn(new TextClock(getContext()));
-        listener.onPluginConnected(plugin2, null);
-        // WHEN the first plugin is disconnected
-        listener.onPluginDisconnected(plugin1);
-        // THEN the view from the second plugin is still a child of KeyguardClockSwitch.
-        assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
-        assertThat(plugin1.getView().getParent()).isNull();
-    }
-
-    @Test
     public void onPluginDisconnected_secondOfTwoDisconnected() {
         // GIVEN two plugins are connected
         ClockPlugin plugin1 = mock(ClockPlugin.class);
         when(plugin1.getView()).thenReturn(new TextClock(getContext()));
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin1, null);
+        Consumer<ClockPlugin> consumer = mKeyguardClockSwitch.getClockPluginConsumer();
+        consumer.accept(plugin1);
         ClockPlugin plugin2 = mock(ClockPlugin.class);
         when(plugin2.getView()).thenReturn(new TextClock(getContext()));
-        listener.onPluginConnected(plugin2, null);
+        consumer.accept(plugin2);
         // WHEN the second plugin is disconnected
-        listener.onPluginDisconnected(plugin2);
+        consumer.accept(null);
         // THEN the default clock should be shown.
         verify(mClockView).setVisibility(VISIBLE);
         assertThat(plugin1.getView().getParent()).isNull();
@@ -246,8 +213,7 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
 
         mKeyguardClockSwitch.setTextColor(Color.WHITE);
 
@@ -271,8 +237,7 @@
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
         Style style = mock(Style.class);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
 
         mKeyguardClockSwitch.setStyle(style);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
index 521d5d1..53ad0b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
@@ -16,17 +16,12 @@
 
 package com.android.systemui;
 
-
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.graphics.Bitmap;
@@ -58,13 +53,15 @@
     @Mock private SurfaceHolder mSurfaceHolder;
     @Mock private DisplayInfo mDisplayInfo;
 
-    CountDownLatch mEventCountdown;
+    private CountDownLatch mEventCountdown;
+    private CountDownLatch mAmbientEventCountdown;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         mEventCountdown = new CountDownLatch(1);
+        mAmbientEventCountdown = new CountDownLatch(2);
 
         mImageWallpaper = new ImageWallpaper() {
             @Override
@@ -86,6 +83,11 @@
                         assertTrue("mFixedSizeAllowed should be true", allowed);
                         mEventCountdown.countDown();
                     }
+
+                    @Override
+                    public void onAmbientModeChanged(boolean inAmbientMode, long duration) {
+                        mAmbientEventCountdown.countDown();
+                    }
                 };
             }
         };
@@ -132,4 +134,23 @@
         verify(mSurfaceHolder, times(1)).setFixedSize(ImageWallpaper.DrawableEngine.MIN_BACKGROUND_WIDTH, ImageWallpaper.DrawableEngine.MIN_BACKGROUND_HEIGHT);
     }
 
+    @Test
+    public void testDeliversAmbientModeChanged() {
+        ImageWallpaper.DrawableEngine wallpaperEngine =
+                (ImageWallpaper.DrawableEngine) mImageWallpaper.onCreateEngine();
+
+        assertEquals("setFixedSizeAllowed should have been called.",
+                0, mEventCountdown.getCount());
+
+        wallpaperEngine.setCreated(true);
+        wallpaperEngine.doAmbientModeChanged(false, 1000);
+        assertFalse("ambient mode should be false", wallpaperEngine.isInAmbientMode());
+        assertEquals("onAmbientModeChanged should have been called.",
+                1, mAmbientEventCountdown.getCount());
+
+        wallpaperEngine.doAmbientModeChanged(true, 1000);
+        assertTrue("ambient mode should be true", wallpaperEngine.isInAmbientMode());
+        assertEquals("onAmbientModeChanged should have been called.",
+                0, mAmbientEventCountdown.getCount());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index ecb0cf8..f6791dd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -45,7 +45,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.INotificationManager;
@@ -73,6 +72,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -498,12 +498,15 @@
     }
 
     @Test
-    public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception {
+    public void testLogBlockingHelperCounter_logGutsViewDisplayed() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT);
         mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
-        verifyZeroInteractions(mMetricsLogger);
+        verify(mMetricsLogger).write(argThat(logMaker ->
+                logMaker.getType() == MetricsEvent.NOTIFICATION_BLOCKING_HELPER
+                        && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_DISPLAY
+        ));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 214404c..c140ba2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -142,6 +142,7 @@
         doNothing().when(mGroupManager).collapseAllGroups();
         doNothing().when(mExpandHelper).cancelImmediately();
         doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
+        doNothing().when(notificationShelf).fadeInTranslating();
 
         mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index add8838..a72be7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -57,13 +57,15 @@
     @Before
     public void setup() {
         mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
-        mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
+        StatusBar statusBar = mock(StatusBar.class);
+        mSysuiContext.putComponent(StatusBar.class, statusBar);
         mSysuiContext.putComponent(TunerService.class, mock(TunerService.class));
         mStatusBarStateController = mDependency
                 .injectMockDependency(StatusBarStateController.class);
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
         mMockNotificiationAreaController = mock(NotificationIconAreaController.class);
         mNotificationAreaInner = mock(View.class);
+        when(statusBar.getPanel()).thenReturn(mock(NotificationPanelView.class));
         when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
         when(mMockNotificiationAreaController.getNotificationInnerAreaView()).thenReturn(
                 mNotificationAreaInner);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
new file mode 100644
index 0000000..b7b95ef
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.phone;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationPanelViewTest extends SysuiTestCase {
+
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private NotificationStackScrollLayout mNotificationStackScrollLayout;
+    @Mock
+    private KeyguardStatusView mKeyguardStatusView;
+    private NotificationPanelView mNotificationPanelView;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mDependency.injectTestDependency(StatusBarStateController.class,
+                mStatusBarStateController);
+        mDependency.injectMockDependency(ShadeController.class);
+        mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
+        mDependency.injectMockDependency(ConfigurationController.class);
+        mDependency.injectMockDependency(ZenModeController.class);
+        mNotificationPanelView = new TestableNotificationPanelView();
+    }
+
+    @Test
+    public void testSetDozing_notifiesNsslAndStateController() {
+        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+        InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController);
+        inOrder.verify(mNotificationStackScrollLayout).setDark(eq(true), eq(true), eq(null));
+        inOrder.verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+        inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true));
+    }
+
+    @Test
+    public void testSetDozing_showsDarkShelfWithDefaultClock() {
+        when(mKeyguardStatusView.hasCustomClock()).thenReturn(false);
+        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+        verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+    }
+
+    @Test
+    public void testSetDozing_hidesDarkShelfWhenCustomClock() {
+        when(mKeyguardStatusView.hasCustomClock()).thenReturn(true);
+        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+        verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(false));
+    }
+
+    private class TestableNotificationPanelView extends NotificationPanelView {
+        TestableNotificationPanelView() {
+            super(NotificationPanelViewTest.this.mContext, null);
+            mNotificationStackScroller = mNotificationStackScrollLayout;
+            mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index 2805908..382dde9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -97,6 +97,7 @@
         doReturn(HIT_TARGET_NONE).when(mNavigationBarView).getDownHitTarget();
         doReturn(backButton).when(mNavigationBarView).getBackButton();
         doReturn(mResources).when(mNavigationBarView).getResources();
+        doReturn(mContext).when(mNavigationBarView).getContext();
 
         mController = new QuickStepController(mContext);
         mController.setComponents(mNavigationBarView);
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 146c5d6..8eb42c4 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
@@ -54,7 +54,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.function.Consumer;
 
@@ -94,6 +94,7 @@
                 },
                 visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager);
         mScrimController.setHasBackdrop(false);
+        mScrimController.setWallpaperSupportsAmbientMode(false);
     }
 
     @Test
@@ -474,6 +475,26 @@
     }
 
     @Test
+    public void testHoldsPulsingWallpaperAnimationLock() {
+        // Pre-conditions
+        mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {
+            @Override
+            public boolean isFadeOutWallpaper() {
+                return true;
+            }
+        });
+        mScrimController.finishAnimationsImmediately();
+        reset(mWakeLock);
+
+        mScrimController.onHideWallpaperTimeout();
+        verify(mWakeLock).acquire();
+        verify(mWakeLock, never()).release();
+        mScrimController.finishAnimationsImmediately();
+        verify(mWakeLock).release();
+        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+    }
+
+    @Test
     public void testWillHideAodWallpaper() {
         mScrimController.setWallpaperSupportsAmbientMode(true);
         mScrimController.transitionTo(ScrimState.AOD);
@@ -483,6 +504,34 @@
     }
 
     @Test
+    public void testWillHidePulsingWallpaper_withRequestFadeOut() {
+        mScrimController.setWallpaperSupportsAmbientMode(true);
+        mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {
+            @Override
+            public boolean isFadeOutWallpaper() {
+                return true;
+            }
+        });
+        verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any());
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
+    }
+
+    @Test
+    public void testDoesNotHidePulsingWallpaper_withoutRequestFadeOut() {
+        mScrimController.setWallpaperSupportsAmbientMode(true);
+        mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {});
+        verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
+    }
+
+    @Test
+    public void testDoesNotHidePulsingWallpaper_withoutCallback() {
+        mScrimController.setWallpaperSupportsAmbientMode(true);
+        mScrimController.transitionTo(ScrimState.PULSING);
+        verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
+    }
+
+    @Test
     public void testConservesExpansionOpacityAfterTransition() {
         mScrimController.transitionTo(ScrimState.UNLOCKED);
         mScrimController.setPanelExpansion(0.5f);
@@ -578,7 +627,7 @@
     @Test
     public void testEatsTouchEvent() {
         HashSet<ScrimState> eatsTouches =
-                new HashSet<>(Arrays.asList(ScrimState.AOD, ScrimState.PULSING));
+                new HashSet<>(Collections.singletonList(ScrimState.AOD));
         for (ScrimState state : ScrimState.values()) {
             if (state == ScrimState.UNINITIALIZED) {
                 continue;
@@ -738,5 +787,4 @@
             callback.run();
         }
     }
-
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
deleted file mode 100644
index 5c34730..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
+++ /dev/null
@@ -1,177 +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.statusbar.policy;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
-        .RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS;
-
-import static org.junit.Assert.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import static java.lang.Thread.sleep;
-
-import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.MessageHandler;
-import android.testing.TestableLooper.RunWithLooper;
-import android.util.Log;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-@SmallTest
-public class IconLoggerImplTest extends SysuiTestCase {
-
-    private MetricsLogger mMetricsLogger;
-    private IconLoggerImpl mIconLogger;
-    private TestableLooper mTestableLooper;
-    private MessageHandler mMessageHandler;
-
-    @Before
-    public void setup() {
-        IconLoggerImpl.MIN_LOG_INTERVAL = 5; // Low interval for testing
-        mMetricsLogger = mock(MetricsLogger.class);
-        mTestableLooper = TestableLooper.get(this);
-        mMessageHandler = mock(MessageHandler.class);
-        mTestableLooper.setMessageHandler(mMessageHandler);
-        String[] iconArray = new String[] {
-                "test_icon_1",
-                "test_icon_2",
-        };
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.array.config_statusBarIcons, iconArray);
-        mIconLogger = new IconLoggerImpl(mContext, mTestableLooper.getLooper(), mMetricsLogger);
-        when(mMessageHandler.onMessageHandled(any())).thenReturn(true);
-        clearInvocations(mMetricsLogger);
-    }
-
-    @Test
-    public void testIconShown() throws InterruptedException {
-        // Should only get one message, for the same icon shown twice.
-        mIconLogger.onIconShown("test_icon_2");
-        mIconLogger.onIconShown("test_icon_2");
-
-        // There should be some delay before execute.
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, never()).onMessageHandled(any());
-
-        sleep(10);
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, times(1)).onMessageHandled(any());
-    }
-
-    @Test
-    public void testIconHidden() throws InterruptedException {
-        // Add the icon so that it can be removed.
-        mIconLogger.onIconShown("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-        clearInvocations(mMessageHandler);
-
-        // Should only get one message, for the same icon shown twice.
-        mIconLogger.onIconHidden("test_icon_2");
-        mIconLogger.onIconHidden("test_icon_2");
-
-        // There should be some delay before execute.
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, never()).onMessageHandled(any());
-
-        sleep(10);
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, times(1)).onMessageHandled(any());
-    }
-
-    @Test
-    public void testLog() throws InterruptedException {
-        mIconLogger.onIconShown("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if (IconLoggerImpl.MIN_LOG_INTERVAL >
-                    (long) maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS)) {
-                Log.e("IconLoggerImplTest", "Invalid latency "
-                        + maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS));
-                return false;
-            }
-            if (1 != (int) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid icon count "
-                        + maker.getTaggedData(FIELD_NUM_STATUS_ICONS));
-                return false;
-            }
-            return true;
-        }));
-    }
-
-    @Test
-    public void testBitField() throws InterruptedException {
-        mIconLogger.onIconShown("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if ((1 << 1) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
-                        (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
-                return false;
-            }
-            return true;
-        }));
-
-        mIconLogger.onIconShown("test_icon_1");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if ((1 << 1 | 1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
-                        (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
-                return false;
-            }
-            return true;
-        }));
-
-        mIconLogger.onIconHidden("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if ((1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
-                        (Integer) maker.getTaggedData(FIELD_STATUS_ICONS)));
-                return false;
-            }
-            return true;
-        }));
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
index 37a56a3..3cbf902 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -54,6 +54,7 @@
                 R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts, 7);
         resources.addOverride(
                 R.bool.config_smart_replies_in_notifications_edit_choices_before_sending, false);
+        resources.addOverride(R.bool.config_smart_replies_in_notifications_show_in_heads_up, true);
         mConstants = new SmartReplyConstants(Handler.createAsync(Looper.myLooper()), mContext);
     }
 
@@ -152,6 +153,26 @@
                         RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED));
     }
 
+    @Test
+    public void testShowInHeadsUpWithNoConfig() {
+        assertTrue(mConstants.isEnabled());
+        assertTrue(mConstants.getShowInHeadsUp());
+    }
+
+    @Test
+    public void testShowInHeadsUpEnabled() {
+        overrideSetting("enabled=true,show_in_heads_up=true");
+        triggerConstantsOnChange();
+        assertTrue(mConstants.getShowInHeadsUp());
+    }
+
+    @Test
+    public void testShowInHeadsUpDisabled() {
+        overrideSetting("enabled=true,show_in_heads_up=false");
+        triggerConstantsOnChange();
+        assertFalse(mConstants.getShowInHeadsUp());
+    }
+
     private void overrideSetting(String flags) {
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, flags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java
new file mode 100644
index 0000000..c44a366
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.wallpaper;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.FeatureFlagUtils;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AodMaskViewTest extends SysuiTestCase {
+    private AodMaskView mMaskView;
+    private DisplayInfo mDisplayInfo;
+    private ImageWallpaperTransformer mTransformer;
+
+    @Before
+    public void setUp() throws Exception {
+        DisplayManager displayManager =
+                spy((DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE));
+        doNothing().when(displayManager).registerDisplayListener(any(), any());
+        mContext.addMockSystemService(DisplayManager.class, displayManager);
+
+        WallpaperManager wallpaperManager =
+                spy((WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE));
+        doReturn(null).when(wallpaperManager).getWallpaperInfo();
+        mContext.addMockSystemService(WallpaperManager.class, wallpaperManager);
+
+        mTransformer = spy(new ImageWallpaperTransformer(null /* listener */));
+        mMaskView = spy(new AodMaskView(getContext(), null /* attrs */, mTransformer));
+        mDisplayInfo = new DisplayInfo();
+
+        ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
+                .getDefaultDisplay().getDisplayInfo(mDisplayInfo);
+
+        FeatureFlagUtils.setEnabled(
+                mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED, true);
+    }
+
+    @After
+    public void tearDown() {
+        FeatureFlagUtils.setEnabled(
+                mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED, false);
+    }
+
+    @Test
+    public void testCreateMaskView_TransformerIsNotNull() {
+        assertNotNull("mTransformer should not be null", mTransformer);
+    }
+
+    @Test
+    public void testAodMaskView_ShouldNotClickable() {
+        assertFalse("MaskView should not be clickable", mMaskView.isClickable());
+    }
+
+    @Test
+    public void testAodMaskView_OnSizeChange_ShouldUpdateTransformerOffsets() {
+        mMaskView.onSizeChanged(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, 0, 0);
+        verify(mTransformer, times(1)).updateOffsets();
+    }
+
+    @Test
+    public void testAodMaskView_OnDraw_ShouldDrawTransformedImage() {
+        Canvas c = new Canvas();
+        RectF bounds = new RectF(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+        mMaskView.onSizeChanged(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, 0, 0);
+        mMaskView.onStatePreChange(0, 1);
+        mMaskView.onDraw(c);
+        verify(mTransformer, times(1)).drawTransformedImage(c, null, null, bounds);
+    }
+
+    @Test
+    public void testAodMaskView_IsDozing_ShouldUpdateAmbientModeState() {
+        doNothing().when(mMaskView).setAnimatorProperty(anyBoolean());
+        mMaskView.onStatePreChange(0, 1);
+        mMaskView.onDozingChanged(true);
+        verify(mTransformer, times(1)).updateAmbientModeState(true);
+    }
+
+    @Test
+    public void testAodMaskView_IsDozing_ShouldDoTransitionOrDrawFinalFrame() {
+        doNothing().when(mMaskView).setAnimatorProperty(anyBoolean());
+        mMaskView.onStatePreChange(0, 1);
+        mMaskView.onDozingChanged(true);
+        mMaskView.onStatePostChange();
+        mMaskView.onDozingChanged(false);
+        verify(mMaskView, times(1)).invalidate();
+        verify(mMaskView, times(1)).setAnimatorProperty(false);
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java
new file mode 100644
index 0000000..55b0aae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 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.wallpaper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ImageWallpaperTransformerTest extends SysuiTestCase {
+    private DisplayInfo mDisplayInfo;
+    private Bitmap mBitmap;
+    private Canvas mCanvas;
+    private RectF mDestination;
+
+    @Before
+    public void setUp() throws Exception {
+        mDisplayInfo = new DisplayInfo();
+        ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
+                .getDefaultDisplay().getDisplayInfo(mDisplayInfo);
+        int dimension = Math.max(mDisplayInfo.logicalHeight, mDisplayInfo.logicalWidth);
+        mBitmap = Bitmap.createBitmap(dimension, dimension, Bitmap.Config.ARGB_8888);
+        mCanvas = new Canvas(mBitmap);
+        mCanvas.drawColor(Color.RED);
+        mDestination = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+    }
+
+    @Test
+    public void testVignetteFilter() {
+        VignetteFilter vignette = new VignetteFilter();
+
+        ImageWallpaperTransformer transformer = getTransformer(vignette);
+        transformer.drawTransformedImage(mCanvas, mBitmap, null, mDestination);
+
+        PointF center = vignette.getCenterPoint();
+        int p1 = mBitmap.getPixel((int) center.x, (int) center.y);
+        int p2 = mBitmap.getPixel(0, 0);
+        int p3 = mBitmap.getPixel(mBitmap.getWidth() - 1, mBitmap.getHeight() - 1);
+
+        assertThat(p1).isEqualTo(Color.RED);
+        assertThat(p2 | p3).isEqualTo(Color.BLACK);
+    }
+
+    @Test
+    public void testScrimFilter() {
+        getTransformer(new ScrimFilter())
+                .drawTransformedImage(mCanvas, mBitmap, null, mDestination);
+
+        int pixel = mBitmap.getPixel(0, 0);
+
+        // 0xff4d0000 is the result of 70% alpha pre-multiplied which is 0.7*(0,0,0)+0.3*(255,0,0).
+        assertThat(pixel).isEqualTo(0xff4d0000);
+    }
+
+    private ImageWallpaperTransformer getTransformer(ImageWallpaperFilter filter) {
+        ImageWallpaperTransformer transformer = new ImageWallpaperTransformer(null);
+        transformer.addFilter(filter);
+        transformer.updateDisplayInfo(mDisplayInfo);
+        transformer.updateOffsets();
+        transformer.updateAmbientModeState(true);
+        return transformer;
+    }
+}
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index 25f16e3..45d8458 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -21,7 +21,7 @@
     <string name="legacy_title" msgid="192936250066580964">"ভিপিএন সংযোগ হৈ আছে"</string>
     <string name="session" msgid="6470628549473641030">"ছেশ্বন:"</string>
     <string name="duration" msgid="3584782459928719435">"সময়সীমা:"</string>
-    <string name="data_transmitted" msgid="7988167672982199061">"পঠিওৱা হ\'ল:"</string>
+    <string name="data_transmitted" msgid="7988167672982199061">"পঠিওৱা হ’ল:"</string>
     <string name="data_received" msgid="4062776929376067820">"পোৱা গ\'ল:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_1">%2$s</xliff:g> পেকেট / <xliff:g id="NUMBER_0">%1$s</xliff:g> বাইট"</string>
     <string name="always_on_disconnected_title" msgid="1906740176262776166">"সদা-সক্ৰিয় ভিপিএনৰ লগত সংযোগ কৰিবপৰা নাই"</string>
diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml
index 5019a06..b716c35 100644
--- a/packages/VpnDialogs/res/values-ne/strings.xml
+++ b/packages/VpnDialogs/res/values-ne/strings.xml
@@ -25,7 +25,7 @@
     <string name="data_received" msgid="4062776929376067820">"प्राप्त भयो:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> बाइटहरू / <xliff:g id="NUMBER_1">%2$s</xliff:g> प्याकेटहरू"</string>
     <string name="always_on_disconnected_title" msgid="1906740176262776166">"सधैँ-सक्रिय रहने VPN सेवामा जडान गर्न सकिँदैन"</string>
-    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> लाई सधैँ जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। तपाईंको फोन <xliff:g id="VPN_APP_1">%1$s</xliff:g> मा पुन: जडान नहुँदासम्म यसले कुनै सार्वजनिक नेटवर्क प्रयोग गर्नेछ।"</string>
+    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> लाई सधैँ जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। तपाईंको फोन <xliff:g id="VPN_APP_1">%1$s</xliff:g> मा पुन: जडान नहुँदासम्म यसले कुनै सार्वजनिक नेटवर्क प्रयोग गर्ने छ।"</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> लाई सधैँ पनि जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। VPN पुन: जडान नहुँदासम्म तपाईंसँग कुनै पनि इन्टरनेट रहनेछैन।"</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN सम्बन्धी सेटिङहरू परिवर्तन गर्नुहोस्"</string>
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index a40cf1c..d969c69 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -16,6 +16,9 @@
 
 #define LOG_TAG "PacProcessor"
 
+#include <stdlib.h>
+#include <string>
+
 #include <utils/Log.h>
 #include <utils/Mutex.h>
 #include "android_runtime/AndroidRuntime.h"
@@ -23,24 +26,24 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
-#include "proxy_resolver_v8.h"
+#include "proxy_resolver_v8_wrapper.h"
 
 namespace android {
 
-net::ProxyResolverV8* proxyResolver = NULL;
+ProxyResolverV8Handle* proxyResolver = NULL;
 bool pacSet = false;
 
-String16 jstringToString16(JNIEnv* env, jstring jstr) {
+std::u16string jstringToString16(JNIEnv* env, jstring jstr) {
     const jchar* str = env->GetStringCritical(jstr, 0);
-    String16 str16(reinterpret_cast<const char16_t*>(str),
+    std::u16string str16(reinterpret_cast<const char16_t*>(str),
                    env->GetStringLength(jstr));
     env->ReleaseStringCritical(jstr, str);
     return str16;
 }
 
-jstring string16ToJstring(JNIEnv* env, String16 string) {
-    const char16_t* str = string.string();
-    size_t len = string.size();
+jstring string16ToJstring(JNIEnv* env, std::u16string string) {
+    const char16_t* str = string.data();
+    size_t len = string.length();
 
     return env->NewString(reinterpret_cast<const jchar*>(str), len);
 }
@@ -48,7 +51,7 @@
 static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver == NULL) {
-        proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault());
+        proxyResolver = ProxyResolverV8Handle_new();
         pacSet = false;
         return JNI_FALSE;
     }
@@ -58,7 +61,7 @@
 static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver != NULL) {
-        delete proxyResolver;
+        ProxyResolverV8Handle_delete(proxyResolver);
         proxyResolver = NULL;
         return JNI_FALSE;
     }
@@ -67,14 +70,14 @@
 
 static jboolean com_android_pacprocessor_PacNative_setProxyScriptNativeLocked(JNIEnv* env, jobject,
         jstring script) {
-    String16 script16 = jstringToString16(env, script);
+    std::u16string script16 = jstringToString16(env, script);
 
     if (proxyResolver == NULL) {
         ALOGE("V8 Parser not started when setting PAC script");
         return JNI_TRUE;
     }
 
-    if (proxyResolver->SetPacScript(script16) != OK) {
+    if (ProxyResolverV8Handle_SetPacScript(proxyResolver, script16.data()) != OK) {
         ALOGE("Unable to set PAC script");
         return JNI_TRUE;
     }
@@ -85,9 +88,8 @@
 
 static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(JNIEnv* env, jobject,
         jstring url, jstring host) {
-    String16 url16 = jstringToString16(env, url);
-    String16 host16 = jstringToString16(env, host);
-    String16 ret;
+    std::u16string url16 = jstringToString16(env, url);
+    std::u16string host16 = jstringToString16(env, host);
 
     if (proxyResolver == NULL) {
         ALOGE("V8 Parser not initialized when running PAC script");
@@ -99,12 +101,14 @@
         return NULL;
     }
 
-    if (proxyResolver->GetProxyForURL(url16, host16, &ret) != OK) {
-        String8 ret8(ret);
-        ALOGE("Error Running PAC: %s", ret8.string());
+    std::unique_ptr<char16_t, decltype(&free)> result = std::unique_ptr<char16_t, decltype(&free)>(
+        ProxyResolverV8Handle_GetProxyForURL(proxyResolver, url16.data(), host16.data()), &free);
+    if (result.get() == NULL) {
+        ALOGE("Error Running PAC");
         return NULL;
     }
 
+    std::u16string ret(result.get());
     jstring jret = string16ToJstring(env, ret);
 
     return jret;
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 665773c..5b45a08 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -213,6 +213,25 @@
         IOOP_SYNC = 4;
     }
 
+  // Subtypes of notifications blocking helper view
+  // (NOTIFICATION_BLOCKING_HELPER).
+  enum NotificationBlockingHelper {
+    BLOCKING_HELPER_UNKNOWN = 0;
+    BLOCKING_HELPER_DISPLAY = 1;
+    BLOCKING_HELPER_DISMISS = 2;
+    // When the view of the notification blocking helper was triggered by
+    // system.
+    BLOCKING_HELPER_TRIGGERED_BY_SYSTEM = 3;
+    // "block" was clicked.
+    BLOCKING_HELPER_CLICK_BLOCKED = 4;
+    // "stay silent" was clicked.
+    BLOCKING_HELPER_CLICK_STAY_SILENT = 5;
+    // "alert me" was clicked.
+    BLOCKING_HELPER_CLICK_ALERT_ME = 6;
+    // "undo" was clicked (enables the user to undo "stop notification" action).
+    BLOCKING_HELPER_CLICK_UNDO = 7;
+  }
+
   // Known visual elements: views or controls.
   enum View {
     // Unknown view
@@ -5325,7 +5344,7 @@
     // OS: P
     ACCESSIBILITY_VIBRATION = 1292;
 
-    // OPEN: Settings > Accessibility > Vibration > Ring & notification vibration
+    // OPEN: Settings > Accessibility > Vibration > Notification vibration
     // CATEGORY: SETTINGS
     // OS: P
     ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293;
@@ -6763,6 +6782,18 @@
     // OS: Q
     ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED = 1619;
 
+    // OPEN: Settings > Accessibility > Vibration > Ring vibration
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ACCESSIBILITY_VIBRATION_RING = 1620;
+
+    // ACTION: Notification blocking helper view, which helps the user to block
+    // application or channel from showing notifications.
+    // SUBTYPE: NotificationBlockingHelper enum.
+    // CATEGORY: NOTIFICATION
+    // OS: Q
+    NOTIFICATION_BLOCKING_HELPER = 1621;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/Android.bp b/services/Android.bp
index 01734f4..31385ed 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -17,13 +17,16 @@
     static_libs: [
         "services.core",
         "services.accessibility",
+        "services.appprediction",
         "services.appwidget",
         "services.autofill",
         "services.backup",
         "services.companion",
         "services.contentcapture",
+        "services.contentsuggestions",
         "services.coverage",
         "services.devicepolicy",
+        "services.ipmemorystore",
         "services.midi",
         "services.net",
         "services.print",
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 17bf570..6a97fbb 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -32,7 +32,6 @@
 import android.text.TextUtils;
 import android.util.MathUtils;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.view.Display;
 import android.view.MagnificationSpec;
 import android.view.View;
@@ -40,8 +39,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.SomeArgs;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.wm.WindowManagerInternal;
@@ -63,7 +60,7 @@
     private static final String LOG_TAG = "MagnificationController";
 
     public static final float MIN_SCALE = 1.0f;
-    public static final float MAX_SCALE = 5.0f;
+    public static final float MAX_SCALE = 8.0f;
 
     private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
 
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 12e7376..80049e8 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -115,8 +115,11 @@
     private static final boolean DEBUG_PANNING_SCALING = false || DEBUG_ALL;
     private static final boolean DEBUG_EVENT_STREAM = false || DEBUG_ALL;
 
+    // The MIN_SCALE is different from MagnificationController.MIN_SCALE due
+    // to AccessibilityService.MagnificationController#setScale() has
+    // different scale range
     private static final float MIN_SCALE = 2.0f;
-    private static final float MAX_SCALE = 5.0f;
+    private static final float MAX_SCALE = MagnificationController.MAX_SCALE;
 
     @VisibleForTesting final MagnificationController mMagnificationController;
 
diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp
new file mode 100644
index 0000000..a7be587
--- /dev/null
+++ b/services/appprediction/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+    name: "services.appprediction",
+    srcs: ["java/**/*.java"],
+    libs: ["services.core"],
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
new file mode 100644
index 0000000..833eaa0
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -0,0 +1,156 @@
+/*
+ * 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.appprediction;
+
+import static android.Manifest.permission.MANAGE_APP_PREDICTIONS;
+import static android.content.Context.APP_PREDICTION_SERVICE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.app.prediction.IPredictionManager;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+
+import java.io.FileDescriptor;
+import java.util.function.Consumer;
+
+/**
+ * A service used to predict app and shortcut usage.
+ *
+ * <p>The data collected by this service can be analyzed and combined with other sources to provide
+ * predictions in different areas of the system such as Launcher and Share sheet.
+ */
+public class AppPredictionManagerService extends
+        AbstractMasterSystemService<AppPredictionManagerService, AppPredictionPerUserService> {
+
+    private static final String TAG = AppPredictionManagerService.class.getSimpleName();
+
+    private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+    public AppPredictionManagerService(Context context) {
+        super(context, new FrameworkResourcesServiceNameResolver(context,
+                com.android.internal.R.string.config_defaultAppPredictionService), null);
+    }
+
+    @Override
+    protected AppPredictionPerUserService newServiceLocked(int resolvedUserId, boolean disabled) {
+        return new AppPredictionPerUserService(this, mLock, resolvedUserId);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(APP_PREDICTION_SERVICE, new PredictionManagerServiceStub());
+    }
+
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_APP_PREDICTIONS, TAG);
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_DURATION_MS;
+    }
+
+    private class PredictionManagerServiceStub extends IPredictionManager.Stub {
+
+        @Override
+        public void createPredictionSession(@NonNull AppPredictionContext context,
+                @NonNull AppPredictionSessionId sessionId) {
+            runForUserLocked((service) ->
+                    service.onCreatePredictionSessionLocked(context, sessionId));
+        }
+
+        @Override
+        public void notifyAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+                @NonNull AppTargetEvent event) {
+            runForUserLocked((service) -> service.notifyAppTargetEventLocked(sessionId, event));
+        }
+
+        @Override
+        public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+                @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+            runForUserLocked((service) ->
+                    service.notifyLocationShownLocked(sessionId, launchLocation, targetIds));
+        }
+
+        @Override
+        public void sortAppTargets(@NonNull AppPredictionSessionId sessionId,
+                @NonNull ParceledListSlice targets,
+                IPredictionCallback callback) {
+            runForUserLocked((service) ->
+                    service.sortAppTargetsLocked(sessionId, targets, callback));
+        }
+
+        @Override
+        public void registerPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+                @NonNull IPredictionCallback callback) {
+            runForUserLocked((service) ->
+                    service.registerPredictionUpdatesLocked(sessionId, callback));
+        }
+
+        public void unregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+                @NonNull IPredictionCallback callback) {
+            runForUserLocked((service) ->
+                    service.unregisterPredictionUpdatesLocked(sessionId, callback));
+        }
+
+        @Override
+        public void requestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+            runForUserLocked((service) -> service.requestPredictionUpdateLocked(sessionId));
+        }
+
+        @Override
+        public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+            runForUserLocked((service) -> service.onDestroyPredictionSessionLocked(sessionId));
+        }
+
+        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args, @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) throws RemoteException {
+            new AppPredictionManagerServiceShellCommand(AppPredictionManagerService.this)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+
+        private void runForUserLocked(@NonNull Consumer<AppPredictionPerUserService> c) {
+            final int userId = UserHandle.getCallingUserId();
+            // TODO(b/111701043): Determine what permission model we want for this
+            long origId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    final AppPredictionPerUserService service = getServiceForUserLocked(userId);
+                    c.accept(service);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java
new file mode 100644
index 0000000..ed7cc67
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java
@@ -0,0 +1,83 @@
+/*
+ * 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.appprediction;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the AppPredictionManagerService.
+ */
+public class AppPredictionManagerServiceShellCommand extends ShellCommand {
+
+    private static final String TAG =
+            AppPredictionManagerServiceShellCommand.class.getSimpleName();
+
+    private final AppPredictionManagerService mService;
+
+    public AppPredictionManagerServiceShellCommand(@NonNull AppPredictionManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        switch (cmd) {
+            case "set": {
+                final String what = getNextArgRequired();
+                switch (what) {
+                    case "temporary-service": {
+                        final int userId = Integer.parseInt(getNextArgRequired());
+                        String serviceName = getNextArg();
+                        if (serviceName == null) {
+                            mService.resetTemporaryService(userId);
+                            return 0;
+                        }
+                        final int duration = Integer.parseInt(getNextArgRequired());
+                        mService.setTemporaryService(userId, serviceName, duration);
+                        pw.println("AppPredictionService temporarily set to " + serviceName
+                                + " for " + duration + "ms");
+                        break;
+                    }
+                }
+            }
+            break;
+            default:
+                return handleDefaultCommands(cmd);
+        }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter()) {
+            pw.println("AppPredictionManagerService commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implemtation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
new file mode 100644
index 0000000..24d592c
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -0,0 +1,218 @@
+/*
+ * 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.appprediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.service.appprediction.AppPredictionService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.infra.AbstractPerUserSystemService;
+
+/**
+ * Per-user instance of {@link AppPredictionManagerService}.
+ */
+public class AppPredictionPerUserService extends
+        AbstractPerUserSystemService<AppPredictionPerUserService, AppPredictionManagerService>
+             implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
+
+    private static final String TAG = AppPredictionPerUserService.class.getSimpleName();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private RemoteAppPredictionService mRemoteService;
+
+    protected AppPredictionPerUserService(AppPredictionManagerService master,
+            Object lock, int userId) {
+        super(master, lock, userId);
+    }
+
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws NameNotFoundException {
+
+        ServiceInfo si;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException e) {
+            throw new NameNotFoundException("Could not get service for " + serviceComponent);
+        }
+        // TODO(b/111701043): must check that either the service is from a system component,
+        // or it matches a service set by shell cmd (so it can be used on CTS tests and when
+        // OEMs are implementing the real service and also verify the proper permissions
+        return si;
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        final boolean enabledChanged = super.updateLocked(disabled);
+        if (enabledChanged) {
+            if (!isEnabledLocked()) {
+                // Clear the remote service for the next call
+                mRemoteService = null;
+            }
+        }
+        return enabledChanged;
+    }
+
+    /**
+     * Notifies the service of a new prediction session.
+     */
+    @GuardedBy("mLock")
+    public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.onCreatePredictionSession(context, sessionId);
+        }
+    }
+
+    /**
+     * Records an app target event to the service.
+     */
+    @GuardedBy("mLock")
+    public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull AppTargetEvent event) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.notifyAppTargetEvent(sessionId, event);
+        }
+    }
+
+    /**
+     * Records when a launch location is shown.
+     */
+    @GuardedBy("mLock")
+    public void notifyLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.notifyLocationShown(sessionId, launchLocation, targetIds);
+        }
+    }
+
+    /**
+     * Requests the service to sort a list of apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.sortAppTargets(sessionId, targets, callback);
+        }
+    }
+
+    /**
+     * Registers a callback for continuous updates of predicted apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.registerPredictionUpdates(sessionId, callback);
+        }
+    }
+
+    /**
+     * Unregisters a callback for continuous updates of predicted apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.unregisterPredictionUpdates(sessionId, callback);
+        }
+    }
+
+    /**
+     * Requests a new set of predicted apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.requestPredictionUpdate(sessionId);
+        }
+    }
+
+    /**
+     * Notifies the service of the end of an existing prediction session.
+     */
+    @GuardedBy("mLock")
+    public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.onDestroyPredictionSession(sessionId);
+        }
+    }
+
+    @Override
+    public void onFailureOrTimeout(boolean timedOut) {
+        if (isDebug()) {
+            Slog.d(TAG, "onFailureOrTimeout(): timed out=" + timedOut);
+        }
+
+        // Do nothing, we are just proxying to the prediction service
+    }
+
+    @Override
+    public void onServiceDied(RemoteAppPredictionService service) {
+        if (isDebug()) {
+            Slog.d(TAG, "onServiceDied():");
+        }
+
+        // Do nothing, we are just proxying to the prediction service
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteAppPredictionService getRemoteServiceLocked() {
+        if (mRemoteService == null) {
+            final String serviceName = getComponentNameLocked();
+            if (serviceName == null) {
+                if (mMaster.verbose) {
+                    Slog.v(TAG, "getRemoteServiceLocked(): not set");
+                }
+                return null;
+            }
+            ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+            mRemoteService = new RemoteAppPredictionService(getContext(),
+                    AppPredictionService.SERVICE_INTERFACE, serviceComponent, mUserId, this,
+                    mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+        }
+
+        return mRemoteService;
+    }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
new file mode 100644
index 0000000..45ea86f
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -0,0 +1,142 @@
+/*
+ * 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.appprediction;
+
+import android.annotation.NonNull;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.IBinder;
+import android.service.appprediction.IPredictionService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+
+/**
+ * Proxy to the {@link android.service.appprediction.AppPredictionService} implemention in another
+ * process.
+ */
+public class RemoteAppPredictionService extends
+        AbstractMultiplePendingRequestsRemoteService<RemoteAppPredictionService,
+                IPredictionService> {
+
+    private static final String TAG = "RemoteAppPredictionService";
+
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+    public RemoteAppPredictionService(Context context, String serviceInterface,
+            ComponentName componentName, int userId,
+            RemoteAppPredictionServiceCallbacks callback, boolean bindInstantServiceAllowed,
+            boolean verbose) {
+        super(context, serviceInterface, componentName, userId, callback, bindInstantServiceAllowed,
+                verbose, /* initialCapacity= */ 1);
+    }
+
+    @Override
+    protected IPredictionService getServiceInterface(IBinder service) {
+        return IPredictionService.Stub.asInterface(service);
+    }
+
+    @Override
+    protected long getTimeoutIdleBindMillis() {
+        return PERMANENT_BOUND_TIMEOUT_MS;
+    }
+
+    @Override
+    protected long getRemoteRequestMillis() {
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+    }
+
+    /**
+     * Notifies the service of a new prediction session.
+     */
+    public void onCreatePredictionSession(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {
+        scheduleAsyncRequest((s) -> s.onCreatePredictionSession(context, sessionId));
+    }
+
+    /**
+     * Records an app target event to the service.
+     */
+    public void notifyAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+            @NonNull AppTargetEvent event) {
+        scheduleAsyncRequest((s) -> s.notifyAppTargetEvent(sessionId, event));
+    }
+
+    /**
+     * Records when a launch location is shown.
+     */
+    public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+            @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+        scheduleAsyncRequest((s) -> s.notifyLocationShown(sessionId, launchLocation, targetIds));
+    }
+
+    /**
+     * Requests the service to sort a list of apps or shortcuts.
+     */
+    public void sortAppTargets(@NonNull AppPredictionSessionId sessionId,
+            @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
+        scheduleAsyncRequest((s) -> s.sortAppTargets(sessionId, targets, callback));
+    }
+
+
+    /**
+     * Registers a callback for continuous updates of predicted apps or shortcuts.
+     */
+    public void registerPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        scheduleAsyncRequest((s) -> s.registerPredictionUpdates(sessionId, callback));
+    }
+
+    /**
+     * Unregisters a callback for continuous updates of predicted apps or shortcuts.
+     */
+    public void unregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        scheduleAsyncRequest((s) -> s.unregisterPredictionUpdates(sessionId, callback));
+    }
+
+    /**
+     * Requests a new set of predicted apps or shortcuts.
+     */
+    public void requestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+        scheduleAsyncRequest((s) -> s.requestPredictionUpdate(sessionId));
+    }
+
+    /**
+     * Notifies the service of the end of an existing prediction session.
+     */
+    public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+        scheduleAsyncRequest((s) -> s.onDestroyPredictionSession(sessionId));
+    }
+
+    /**
+     * Failure callback
+     */
+    public interface RemoteAppPredictionServiceCallbacks
+            extends VultureCallback<RemoteAppPredictionService> {
+
+        /**
+         * Notifies a the failure or timeout of a remote call.
+         */
+        void onFailureOrTimeout(boolean timedOut);
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 34fe5d9..e8a52b4 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -139,9 +139,6 @@
         if (mPendingRequest == pendingRequest) {
             mPendingRequest = null;
         }
-        if (mPendingRequest == null) {
-            scheduleUnbind();
-        }
         return true;
     }
 
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index d7a2365..6b0adfb 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -850,19 +850,29 @@
             mFullBackupQueue = readFullBackupSchedule();
         }
 
-        // Register for broadcasts about package install, etc., so we can
-        // update the provider list.
+        // Register for broadcasts about package changes.
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
-        mContext.registerReceiver(mBroadcastReceiver, filter);
+        mContext.registerReceiverAsUser(
+                mBroadcastReceiver,
+                UserHandle.of(mUserId),
+                filter,
+                /* broadcastPermission */ null,
+                /* scheduler */ null);
+
         // Register for events related to sdcard installation.
         IntentFilter sdFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
+        mContext.registerReceiverAsUser(
+                mBroadcastReceiver,
+                UserHandle.of(mUserId),
+                sdFilter,
+                /* broadcastPermission */ null,
+                /* scheduler */ null);
     }
 
     private ArrayList<FullBackupEntry> readFullBackupSchedule() {
@@ -1127,17 +1137,23 @@
         }
     }
 
-    // ----- Track installation/removal of packages -----
+    /**
+     * A {@link BroadcastReceiver} tracking changes to packages and sd cards in order to update our
+     * internal bookkeeping.
+     */
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
-            if (MORE_DEBUG) Slog.d(TAG, "Received broadcast " + intent);
+            if (MORE_DEBUG) {
+                Slog.d(TAG, "Received broadcast " + intent);
+            }
 
             String action = intent.getAction();
             boolean replacing = false;
             boolean added = false;
             boolean changed = false;
             Bundle extras = intent.getExtras();
-            String[] pkgList = null;
+            String[] packageList = null;
+
             if (Intent.ACTION_PACKAGE_ADDED.equals(action)
                     || Intent.ACTION_PACKAGE_REMOVED.equals(action)
                     || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
@@ -1145,69 +1161,70 @@
                 if (uri == null) {
                     return;
                 }
-                final String pkgName = uri.getSchemeSpecificPart();
-                if (pkgName != null) {
-                    pkgList = new String[]{pkgName};
-                }
-                changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
 
-                // At package-changed we only care about looking at new transport states
+                String packageName = uri.getSchemeSpecificPart();
+                if (packageName != null) {
+                    packageList = new String[]{packageName};
+                }
+
+                changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
                 if (changed) {
-                    final String[] components =
+                    // Look at new transport states for package changed events.
+                    String[] components =
                             intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
 
                     if (MORE_DEBUG) {
-                        Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
+                        Slog.i(TAG, "Package " + packageName + " changed");
                         for (int i = 0; i < components.length; i++) {
                             Slog.i(TAG, "   * " + components[i]);
                         }
                     }
 
                     mBackupHandler.post(
-                            () -> mTransportManager.onPackageChanged(pkgName, components));
-                    return; // nothing more to do in the PACKAGE_CHANGED case
+                            () -> mTransportManager.onPackageChanged(packageName, components));
+                    return;
                 }
 
                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
                 added = true;
-                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                 added = false;
-                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             }
 
-            if (pkgList == null || pkgList.length == 0) {
+            if (packageList == null || packageList.length == 0) {
                 return;
             }
 
-            final int uid = extras.getInt(Intent.EXTRA_UID);
+            int uid = extras.getInt(Intent.EXTRA_UID);
             if (added) {
                 synchronized (mBackupParticipants) {
                     if (replacing) {
-                        // This is the package-replaced case; we just remove the entry
-                        // under the old uid and fall through to re-add.  If an app
-                        // just added key/value backup participation, this picks it up
-                        // as a known participant.
-                        removePackageParticipantsLocked(pkgList, uid);
+                        // Remove the entry under the old uid and fall through to re-add. If an app
+                        // just opted into key/value backup, add it as a known participant.
+                        removePackageParticipantsLocked(packageList, uid);
                     }
-                    addPackageParticipantsLocked(pkgList);
+                    addPackageParticipantsLocked(packageList);
                 }
-                // If they're full-backup candidates, add them there instead
-                final long now = System.currentTimeMillis();
-                for (final String packageName : pkgList) {
+
+                long now = System.currentTimeMillis();
+                for (String packageName : packageList) {
                     try {
-                        PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
+                        PackageInfo app =
+                                mPackageManager.getPackageInfoAsUser(
+                                        packageName, /* flags */ 0, mUserId);
                         if (AppBackupUtils.appGetsFullBackup(app)
                                 && AppBackupUtils.appIsEligibleForBackup(
                                 app.applicationInfo, mPackageManager)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob(0);
                         } else {
-                            // The app might have just transitioned out of full-data into
-                            // doing key/value backups, or might have just disabled backups
-                            // entirely.  Make sure it is no longer in the full-data queue.
+                            // The app might have just transitioned out of full-data into doing
+                            // key/value backups, or might have just disabled backups entirely. Make
+                            // sure it is no longer in the full-data queue.
                             synchronized (mQueueLock) {
                                 dequeueFullBackupLocked(packageName);
                             }
@@ -1216,32 +1233,28 @@
 
                         mBackupHandler.post(
                                 () -> mTransportManager.onPackageAdded(packageName));
-
                     } catch (NameNotFoundException e) {
-                        // doesn't really exist; ignore it
                         if (DEBUG) {
                             Slog.w(TAG, "Can't resolve new app " + packageName);
                         }
                     }
                 }
 
-                // Whenever a package is added or updated we need to update
-                // the package metadata bookkeeping.
+                // Whenever a package is added or updated we need to update the package metadata
+                // bookkeeping.
                 dataChangedImpl(PACKAGE_MANAGER_SENTINEL);
             } else {
-                if (replacing) {
-                    // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
-                } else {
-                    // Outright removal.  In the full-data case, the app will be dropped
-                    // from the queue when its (now obsolete) name comes up again for
-                    // backup.
+                if (!replacing) {
+                    // Outright removal. In the full-data case, the app will be dropped from the
+                    // queue when its (now obsolete) name comes up again for backup.
                     synchronized (mBackupParticipants) {
-                        removePackageParticipantsLocked(pkgList, uid);
+                        removePackageParticipantsLocked(packageList, uid);
                     }
                 }
-                for (final String pkgName : pkgList) {
+
+                for (String packageName : packageList) {
                     mBackupHandler.post(
-                            () -> mTransportManager.onPackageRemoved(pkgName));
+                            () -> mTransportManager.onPackageRemoved(packageName));
                 }
             }
         }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 4b24ef9..dc0f602 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -39,6 +39,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -50,8 +51,9 @@
 /**
  * A service used to observe the contents of the screen.
  *
- * <p>The data collected by this service can be analyzed and combined with other sources to provide
- * contextual data in other areas of the system such as Autofill.
+ * <p>The data collected by this service can be analyzed on-device and combined
+ * with other sources to provide contextual data in other areas of the system
+ * such as Autofill.
  */
 public final class ContentCaptureManagerService extends
         AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> {
@@ -196,6 +198,22 @@
         }
 
         @Override
+        public void getReceiverServiceComponentName(@UserIdInt int userId,
+                IResultReceiver receiver) {
+            ComponentName connectedServiceComponentName;
+            synchronized (mLock) {
+                final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+                connectedServiceComponentName = service.getServiceComponentName();
+            }
+            try {
+                receiver.send(0, SyncResultReceiver.bundleFor(connectedServiceComponentName));
+            } catch (RemoteException e) {
+                // Ignore exception as we need to be resilient against app behavior.
+                Slog.w(TAG, "Unable to send service component name: " + e);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp
new file mode 100644
index 0000000..fc09d2e
--- /dev/null
+++ b/services/contentsuggestions/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+    name: "services.contentsuggestions",
+    srcs: ["java/**/*.java"],
+    libs: ["services.core"],
+}
\ No newline at end of file
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
new file mode 100644
index 0000000..58dbea4
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -0,0 +1,205 @@
+/*
+ * 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.contentsuggestions;
+
+import static android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.IContentSuggestionsManager;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.FileDescriptor;
+
+/**
+ * The system service for providing recents / overview with content suggestion selections and
+ * classifications.
+ *
+ * <p>Calls are received here from
+ * {@link android.app.contentsuggestions.ContentSuggestionsManager} then delegated to
+ * a per user version of the service. From there they are routed to the remote actual implementation
+ * that provides the suggestion selections and classifications.
+ */
+public class ContentSuggestionsManagerService extends
+        AbstractMasterSystemService<
+                        ContentSuggestionsManagerService, ContentSuggestionsPerUserService> {
+
+    private static final String TAG = ContentSuggestionsManagerService.class.getSimpleName();
+    private static final boolean VERBOSE = false; // TODO: make dynamic
+
+    private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+    public ContentSuggestionsManagerService(Context context) {
+        super(context, new FrameworkResourcesServiceNameResolver(context,
+                com.android.internal.R.string.config_defaultContentSuggestionsService), null);
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+    }
+
+    @Override
+    protected ContentSuggestionsPerUserService newServiceLocked(int resolvedUserId,
+            boolean disabled) {
+        return new ContentSuggestionsPerUserService(this, mLock, resolvedUserId);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(
+                Context.CONTENT_SUGGESTIONS_SERVICE, new ContentSuggestionsManagerStub());
+    }
+
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_CONTENT_SUGGESTIONS, TAG);
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_DURATION_MS;
+    }
+
+    private boolean isCallerRecents(int userId) {
+        if (mServiceNameResolver.isTemporary(userId)) {
+            // If a temporary service is set then skip the recents check
+            return true;
+        }
+        return mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid());
+    }
+
+    private void enforceCallerIsRecents(int userId, String func) {
+        if (isCallerRecents(userId)) {
+            return;
+        }
+
+        String msg = "Permission Denial: " + func + " from pid="
+                + Binder.getCallingPid()
+                + ", uid=" + Binder.getCallingUid()
+                + " expected caller is recents";
+        Slog.w(TAG, msg);
+        throw new SecurityException(msg);
+    }
+
+    private class ContentSuggestionsManagerStub extends IContentSuggestionsManager.Stub {
+        @Override
+        public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+            if (imageContextRequestExtras == null) {
+                throw new IllegalArgumentException("Expected non-null imageContextRequestExtras");
+            }
+
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "provideContextImage");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.provideContextImageLocked(taskId, imageContextRequestExtras);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "provideContextImageLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void suggestContentSelections(
+                @NonNull SelectionsRequest selectionsRequest,
+                @NonNull ISelectionsCallback selectionsCallback) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "suggestContentSelections");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.suggestContentSelectionsLocked(selectionsRequest, selectionsCallback);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "suggestContentSelectionsLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void classifyContentSelections(
+                @NonNull ClassificationsRequest classificationsRequest,
+                @NonNull IClassificationsCallback callback) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "classifyContentSelections");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.classifyContentSelectionsLocked(classificationsRequest, callback);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "classifyContentSelectionsLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "notifyInteraction");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.notifyInteractionLocked(requestId, bundle);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "reportInteractionLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args, @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) throws RemoteException {
+            // Ensure that the caller is the shell process
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid != android.os.Process.SHELL_UID
+                    && callingUid != android.os.Process.ROOT_UID) {
+                Slog.e(TAG, "Expected shell caller");
+                return;
+            }
+            new ContentSuggestionsManagerServiceShellCommand(ContentSuggestionsManagerService.this)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
new file mode 100644
index 0000000..e34f1ea
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
@@ -0,0 +1,84 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the ContentSuggestionsManagerService.
+ */
+public class ContentSuggestionsManagerServiceShellCommand extends ShellCommand {
+
+    private static final String TAG =
+            ContentSuggestionsManagerServiceShellCommand.class.getSimpleName();
+
+    private final ContentSuggestionsManagerService mService;
+
+    public ContentSuggestionsManagerServiceShellCommand(
+            @NonNull ContentSuggestionsManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        switch (cmd) {
+            case "set": {
+                final String what = getNextArgRequired();
+                switch (what) {
+                    case "temporary-service": {
+                        final int userId = Integer.parseInt(getNextArgRequired());
+                        String serviceName = getNextArg();
+                        if (serviceName == null) {
+                            mService.resetTemporaryService(userId);
+                            return 0;
+                        }
+                        final int duration = Integer.parseInt(getNextArgRequired());
+                        mService.setTemporaryService(userId, serviceName, duration);
+                        pw.println("ContentSuggestionsService temporarily set to " + serviceName
+                                + " for " + duration + "ms");
+                        break;
+                    }
+                }
+            }
+            break;
+            default:
+                return handleDefaultCommands(cmd);
+        }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter()) {
+            pw.println("ContentSuggestionsManagerService commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implemtation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
new file mode 100644
index 0000000..385bc6c
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
@@ -0,0 +1,162 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * Per user delegate of {@link ContentSuggestionsManagerService}.
+ *
+ * <p>Main job is to forward calls to the remote implementation that can provide suggestion
+ * selections and classifications.
+ */
+public final class ContentSuggestionsPerUserService extends
+        AbstractPerUserSystemService<
+                        ContentSuggestionsPerUserService, ContentSuggestionsManagerService> {
+    private static final String TAG = ContentSuggestionsPerUserService.class.getSimpleName();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private RemoteContentSuggestionsService mRemoteService;
+
+    @NonNull
+    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+    ContentSuggestionsPerUserService(
+            ContentSuggestionsManagerService master, Object lock, int userId) {
+        super(master, lock, userId);
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws PackageManager.NameNotFoundException {
+        ServiceInfo si;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException e) {
+            throw new PackageManager.NameNotFoundException(
+                    "Could not get service for " + serviceComponent);
+        }
+        return si;
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        final boolean enabledChanged = super.updateLocked(disabled);
+        if (enabledChanged) {
+            if (!isEnabledLocked()) {
+                // Clear the remote service for the next call
+                mRemoteService = null;
+            }
+        }
+        return enabledChanged;
+    }
+
+    @GuardedBy("mLock")
+    void provideContextImageLocked(int taskId, @NonNull Bundle imageContextRequestExtras) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            ActivityManager.TaskSnapshot snapshot =
+                    mActivityTaskManagerInternal.getTaskSnapshot(taskId, false);
+            GraphicBuffer snapshotBuffer = null;
+            if (snapshot != null) {
+                snapshotBuffer = snapshot.getSnapshot();
+            }
+
+            service.provideContextImage(taskId, snapshotBuffer, imageContextRequestExtras);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void suggestContentSelectionsLocked(
+            @NonNull SelectionsRequest selectionsRequest,
+            @NonNull ISelectionsCallback selectionsCallback) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.suggestContentSelections(selectionsRequest, selectionsCallback);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void classifyContentSelectionsLocked(
+            @NonNull ClassificationsRequest classificationsRequest,
+            @NonNull IClassificationsCallback callback) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.classifyContentSelections(classificationsRequest, callback);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void notifyInteractionLocked(@NonNull String requestId, @NonNull Bundle bundle) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.notifyInteraction(requestId, bundle);
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteContentSuggestionsService getRemoteServiceLocked() {
+        if (mRemoteService == null) {
+            final String serviceName = getComponentNameLocked();
+            if (serviceName == null) {
+                if (mMaster.verbose) {
+                    Slog.v(TAG, "getRemoteServiceLocked(): not set");
+                }
+                return null;
+            }
+            ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+            mRemoteService = new RemoteContentSuggestionsService(getContext(),
+                    serviceComponent, mUserId,
+                    new RemoteContentSuggestionsService.Callbacks() {
+                        @Override
+                        public void onServiceDied(
+                                @NonNull RemoteContentSuggestionsService service) {
+                            // TODO(b/120865921): properly implement
+                            Slog.w(TAG, "remote content suggestions service died");
+                        }
+                    }, mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+        }
+
+        return mRemoteService;
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
new file mode 100644
index 0000000..bf48d76
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
@@ -0,0 +1,97 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.service.contentsuggestions.ContentSuggestionsService;
+import android.service.contentsuggestions.IContentSuggestionsService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+/**
+ * Delegates calls from {@link ContentSuggestionsPerUserService} to the remote actual implementation
+ * of the suggestion selection and classification service.
+ */
+public class RemoteContentSuggestionsService extends
+        AbstractMultiplePendingRequestsRemoteService<RemoteContentSuggestionsService,
+                                IContentSuggestionsService> {
+
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+    RemoteContentSuggestionsService(Context context, ComponentName serviceName,
+            int userId, Callbacks callbacks,
+            boolean bindInstantServiceAllowed, boolean verbose) {
+        super(context, ContentSuggestionsService.SERVICE_INTERFACE, serviceName, userId, callbacks,
+                bindInstantServiceAllowed, verbose, /* initialCapacity= */ 1);
+    }
+
+    @Override
+    protected IContentSuggestionsService getServiceInterface(IBinder service) {
+        return IContentSuggestionsService.Stub.asInterface(service);
+    }
+
+    @Override
+    protected long getTimeoutIdleBindMillis() {
+        return PERMANENT_BOUND_TIMEOUT_MS;
+    }
+
+    @Override
+    protected long getRemoteRequestMillis() {
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+    }
+
+    void provideContextImage(int taskId, @Nullable GraphicBuffer contextImage,
+            @NonNull Bundle imageContextRequestExtras) {
+        scheduleAsyncRequest((s) -> s.provideContextImage(taskId, contextImage,
+                imageContextRequestExtras));
+    }
+
+    void suggestContentSelections(
+            @NonNull SelectionsRequest selectionsRequest,
+            @NonNull ISelectionsCallback selectionsCallback) {
+        scheduleAsyncRequest(
+                (s) -> s.suggestContentSelections(selectionsRequest, selectionsCallback));
+    }
+
+    void classifyContentSelections(
+            @NonNull ClassificationsRequest classificationsRequest,
+            @NonNull IClassificationsCallback callback) {
+        scheduleAsyncRequest((s) -> s.classifyContentSelections(classificationsRequest, callback));
+    }
+
+    void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+        scheduleAsyncRequest((s) -> s.notifyInteraction(requestId, bundle));
+    }
+
+    interface Callbacks
+            extends VultureCallback<RemoteContentSuggestionsService> {
+        // NOTE: so far we don't need to notify the callback implementation
+        // (ContentSuggestionsManager) of the request results (success, timeouts, etc..), so this
+        // callback interface is empty.
+    }
+}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 7bbc543..a333381 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -279,7 +279,7 @@
 
                 Slog.d(TAG,
                         "Airplane Mode change - current state:  " + BluetoothAdapter.nameForState(
-                                st));
+                                st) + ", isAirplaneModeOn()=" + isAirplaneModeOn());
 
                 if (isAirplaneModeOn()) {
                     // Clear registered LE apps to force shut-off
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 66ceae4..d0666b9 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -25,6 +25,7 @@
 import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -37,6 +38,8 @@
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkPolicyManager.RULE_NONE;
 import static android.net.NetworkPolicyManager.uidRulesToString;
+import static android.net.NetworkStack.NETWORKSTACK_PACKAGE_NAME;
+import static android.net.shared.NetworkMonitorUtils.isValidationRequired;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IPPROTO_UDP;
@@ -62,6 +65,8 @@
 import android.net.INetd;
 import android.net.INetdEventCallback;
 import android.net.INetworkManagementEventObserver;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
@@ -79,9 +84,11 @@
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.NetworkWatchlistManager;
+import android.net.PrivateDnsConfigParcel;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.UidRange;
@@ -90,12 +97,13 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
+import android.net.shared.NetworkMonitorUtils;
+import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -123,8 +131,8 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.LocalLog;
-import android.util.LocalLog.ReadOnlyLocalLog;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -149,7 +157,6 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.DnsManager;
-import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
 import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.KeepaliveTracker;
@@ -158,7 +165,6 @@
 import com.android.server.connectivity.MultipathPolicyTracker;
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkDiagnostics;
-import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.NetworkNotificationManager;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.PermissionMonitor;
@@ -186,7 +192,6 @@
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -442,6 +447,43 @@
      */
     private static final int EVENT_DATA_SAVER_CHANGED = 40;
 
+     /**
+      * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
+      * been tested.
+      * obj = String representing URL that Internet probe was redirect to, if it was redirected.
+      * arg1 = One of the NETWORK_TESTED_RESULT_* constants.
+      * arg2 = NetID.
+      */
+    public static final int EVENT_NETWORK_TESTED = 41;
+
+    /**
+     * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the private DNS
+     * config was resolved.
+     * obj = PrivateDnsConfig
+     * arg2 = netid
+     */
+    public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42;
+
+    /**
+     * Request ConnectivityService display provisioning notification.
+     * arg1    = Whether to make the notification visible.
+     * arg2    = NetID.
+     * obj     = Intent to be launched when notification selected by user, null if !arg1.
+     */
+    public static final int EVENT_PROVISIONING_NOTIFICATION = 43;
+
+    /**
+     * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
+     * should be shown.
+     */
+    public static final int PROVISIONING_NOTIFICATION_SHOW = 1;
+
+    /**
+     * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
+     * should be hidden.
+     */
+    public static final int PROVISIONING_NOTIFICATION_HIDE = 0;
+
     private static String eventName(int what) {
         return sMagicDecoderRing.get(what, Integer.toString(what));
     }
@@ -506,30 +548,6 @@
     private long mMaxWakelockDurationMs = 0;
     private long mLastWakeLockAcquireTimestamp = 0;
 
-    // Array of <Network,ReadOnlyLocalLogs> tracking network validation and results
-    private static final int MAX_VALIDATION_LOGS = 10;
-    private static class ValidationLog {
-        final Network mNetwork;
-        final String mName;
-        final ReadOnlyLocalLog mLog;
-
-        ValidationLog(Network network, String name, ReadOnlyLocalLog log) {
-            mNetwork = network;
-            mName = name;
-            mLog = log;
-        }
-    }
-    private final ArrayDeque<ValidationLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
-
-    private void addValidationLogs(ReadOnlyLocalLog log, Network network, String name) {
-        synchronized (mValidationLogs) {
-            while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
-                mValidationLogs.removeLast();
-            }
-            mValidationLogs.addFirst(new ValidationLog(network, name, log));
-        }
-    }
-
     private final IpConnectivityLog mMetricsLog;
 
     @GuardedBy("mBandwidthRequests")
@@ -1684,7 +1702,11 @@
             // caller type. Need to re-factor NetdEventListenerService to allow multiple
             // NetworkMonitor registrants.
             if (nai != null && nai.satisfies(mDefaultRequest)) {
-                nai.networkMonitor.sendMessage(NetworkMonitor.EVENT_DNS_NOTIFICATION, returnCode);
+                try {
+                    nai.networkMonitor().notifyDnsResponse(returnCode);
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
             }
         }
     };
@@ -2266,17 +2288,6 @@
 
         if (ArrayUtils.contains(args, SHORT_ARG) == false) {
             pw.println();
-            synchronized (mValidationLogs) {
-                pw.println("mValidationLogs (most recent first):");
-                for (ValidationLog p : mValidationLogs) {
-                    pw.println(p.mNetwork + " - " + p.mName);
-                    pw.increaseIndent();
-                    p.mLog.dump(fd, pw, args);
-                    pw.decreaseIndent();
-                }
-            }
-
-            pw.println();
             pw.println("mNetworkRequestInfoLogs (most recent first):");
             pw.increaseIndent();
             mNetworkRequestInfoLogs.reverseDump(fd, pw, args);
@@ -2455,11 +2466,11 @@
             switch (msg.what) {
                 default:
                     return false;
-                case NetworkMonitor.EVENT_NETWORK_TESTED: {
+                case EVENT_NETWORK_TESTED: {
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
                     if (nai == null) break;
 
-                    final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                    final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID);
                     final boolean wasValidated = nai.lastValidated;
                     final boolean wasDefault = isDefaultNetwork(nai);
 
@@ -2497,7 +2508,7 @@
                     }
                     break;
                 }
-                case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
+                case EVENT_PROVISIONING_NOTIFICATION: {
                     final int netId = msg.arg2;
                     final boolean visible = toBool(msg.arg1);
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
@@ -2530,7 +2541,7 @@
                     }
                     break;
                 }
-                case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
+                case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
                     if (nai == null) break;
 
@@ -2572,8 +2583,61 @@
         }
     }
 
+    private class NetworkMonitorCallbacks extends INetworkMonitorCallbacks.Stub {
+        private final NetworkAgentInfo mNai;
+
+        private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
+            mNai = nai;
+        }
+
+        @Override
+        public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT,
+                    new Pair<>(mNai, networkMonitor)));
+        }
+
+        @Override
+        public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED,
+                    testResult, mNai.network.netId, redirectUrl));
+        }
+
+        @Override
+        public void notifyPrivateDnsConfigResolved(PrivateDnsConfigParcel config) {
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+                    EVENT_PRIVATE_DNS_CONFIG_RESOLVED,
+                    0, mNai.network.netId, PrivateDnsConfig.fromParcel(config)));
+        }
+
+        @Override
+        public void showProvisioningNotification(String action) {
+            final Intent intent = new Intent(action);
+            intent.setPackage(NETWORKSTACK_PACKAGE_NAME);
+
+            final PendingIntent pendingIntent;
+            // Only the system server can register notifications with package "android"
+            final long token = Binder.clearCallingIdentity();
+            try {
+                pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+                    EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_SHOW,
+                    mNai.network.netId,
+                    pendingIntent));
+        }
+
+        @Override
+        public void hideProvisioningNotification() {
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+                    EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE,
+                    mNai.network.netId));
+        }
+    }
+
     private boolean networkRequiresValidation(NetworkAgentInfo nai) {
-        return NetworkMonitor.isValidationRequired(
+        return isValidationRequired(
                 mDefaultRequest.networkCapabilities, nai.networkCapabilities);
     }
 
@@ -2603,10 +2667,14 @@
         // Internet access and therefore also require validation.
         if (!networkRequiresValidation(nai)) return;
 
-        // Notify the NetworkMonitor thread in case it needs to cancel or
+        // Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or
         // schedule DNS resolutions. If a DNS resolution is required the
         // result will be sent back to us.
-        nai.networkMonitor.notifyPrivateDnsSettingsChanged(cfg);
+        try {
+            nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
 
         // With Private DNS bypass support, we can proceed to update the
         // Private DNS config immediately, even if we're in strict mode
@@ -2736,7 +2804,11 @@
             // Disable wakeup packet monitoring for each interface.
             wakeupModifyInterface(iface, nai.networkCapabilities, false);
         }
-        nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+        try {
+            nai.networkMonitor().notifyNetworkDisconnected();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
         mNetworkAgentInfos.remove(nai.messenger);
         nai.maybeStopClat();
         synchronized (mNetworkForNetId) {
@@ -3096,7 +3168,11 @@
             NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
             if (nai == null) return;
             if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return;
-            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_LAUNCH_CAPTIVE_PORTAL_APP);
+            try {
+                nai.networkMonitor().launchCaptivePortalApp();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
         });
     }
 
@@ -3217,6 +3293,11 @@
         return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
     }
 
+    @Override
+    public NetworkRequest getDefaultRequest() {
+        return mDefaultRequest;
+    }
+
     private class InternalHandler extends Handler {
         public InternalHandler(Looper looper) {
             super(looper);
@@ -3247,7 +3328,9 @@
                     break;
                 }
                 case EVENT_REGISTER_NETWORK_AGENT: {
-                    handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
+                    final Pair<NetworkAgentInfo, INetworkMonitor> arg =
+                            (Pair<NetworkAgentInfo, INetworkMonitor>) msg.obj;
+                    handleRegisterNetworkAgent(arg.first, arg.second);
                     break;
                 }
                 case EVENT_REGISTER_NETWORK_REQUEST:
@@ -3305,7 +3388,14 @@
                 }
                 case EVENT_SYSTEM_READY: {
                     for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                        nai.networkMonitor.systemReady = true;
+                        // Might have been called already in handleRegisterNetworkAgent since
+                        // mSystemReady is set before sending EVENT_SYSTEM_READY, but calling
+                        // this several times is fine.
+                        try {
+                            nai.networkMonitor().notifySystemReady();
+                        } catch (RemoteException e) {
+                            e.rethrowFromSystemServer();
+                        }
                     }
                     mMultipathPolicyTracker.start();
                     break;
@@ -3577,7 +3667,11 @@
         if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
             return;
         }
-        nai.networkMonitor.forceReevaluation(uid);
+        try {
+            nai.networkMonitor().forceReevaluation(uid);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     @Override
@@ -4785,27 +4879,49 @@
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
+                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this);
         // Make sure the network capabilities reflect what the agent info says.
         nai.networkCapabilities = mixInCapabilities(nai, nc);
-        synchronized (this) {
-            nai.networkMonitor.systemReady = mSystemReady;
-        }
         final String extraInfo = networkInfo.getExtraInfo();
         final String name = TextUtils.isEmpty(extraInfo)
                 ? nai.networkCapabilities.getSSID() : extraInfo;
-        addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
         if (DBG) log("registerNetworkAgent " + nai);
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mContext.getSystemService(NetworkStack.class)
+                    .makeNetworkMonitor(nai.network, name, new NetworkMonitorCallbacks(nai));
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        // NetworkAgentInfo registration will finish when the NetworkMonitor is created.
+        // If the network disconnects or sends any other event before that, messages are deferred by
+        // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
+        // registration.
         return nai.network.netId;
     }
 
-    private void handleRegisterNetworkAgent(NetworkAgentInfo nai) {
+    private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
+        nai.onNetworkMonitorCreated(networkMonitor);
         if (VDBG) log("Got NetworkAgent Messenger");
         mNetworkAgentInfos.put(nai.messenger, nai);
         synchronized (mNetworkForNetId) {
             mNetworkForNetId.put(nai.network.netId, nai);
         }
+        synchronized (this) {
+            if (mSystemReady) {
+                try {
+                    networkMonitor.notifySystemReady();
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
+            }
+        }
+
+        try {
+            networkMonitor.start();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
         nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
         NetworkInfo networkInfo = nai.networkInfo;
         nai.networkInfo = null;
@@ -4855,6 +4971,11 @@
             networkAgent.updateClat(mNMS);
             notifyIfacesChangedForNetworkStats();
             if (networkAgent.everConnected) {
+                try {
+                    networkAgent.networkMonitor().notifyLinkPropertiesChanged();
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
                 notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
             }
         }
@@ -5092,6 +5213,11 @@
             // If the requestable capabilities have changed or the score changed, we can't have been
             // called by rematchNetworkAndRequests, so it's safe to start a rematch.
             rematchAllNetworksAndRequests(nai, oldScore);
+            try {
+                nai.networkMonitor().notifyNetworkCapabilitiesChanged();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
@@ -5339,6 +5465,11 @@
         }
 
         if (capabilitiesChanged) {
+            try {
+                nai.networkMonitor().notifyNetworkCapabilitiesChanged();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
@@ -5739,7 +5870,15 @@
             updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties),
                     null);
 
-            networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
+            // Until parceled LinkProperties are sent directly to NetworkMonitor, the connect
+            // command must be sent after updating LinkProperties to maximize chances of
+            // NetworkMonitor seeing the correct LinkProperties when starting.
+            // TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call.
+            try {
+                networkAgent.networkMonitor().notifyNetworkConnected();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             scheduleUnvalidatedPrompt(networkAgent);
 
             if (networkAgent.isVPN()) {
@@ -6020,7 +6159,7 @@
     @Override
     public String getCaptivePortalServerUrl() {
         enforceConnectivityInternalPermission();
-        return NetworkMonitor.getCaptivePortalServerHttpUrl(mContext);
+        return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext);
     }
 
     @Override
@@ -6113,12 +6252,6 @@
     }
 
     @VisibleForTesting
-    public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
-            NetworkAgentInfo nai, NetworkRequest defaultRequest) {
-        return new NetworkMonitor(context, handler, nai, defaultRequest);
-    }
-
-    @VisibleForTesting
     MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
         return new MultinetworkPolicyTracker(c, h, r);
     }
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index ea80ac1..80fda19 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -16,6 +16,22 @@
 
 package com.android.server;
 
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.FastImmutableArraySet;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.util.MutableInt;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.FastPrintWriter;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -25,23 +41,6 @@
 import java.util.List;
 import java.util.Set;
 
-import android.net.Uri;
-import android.util.FastImmutableArraySet;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.MutableInt;
-import android.util.PrintWriterPrinter;
-import android.util.Slog;
-import android.util.LogPrinter;
-import android.util.Printer;
-
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.util.FastPrintWriter;
-
 /**
  * {@hide}
  */
@@ -788,6 +787,7 @@
                         + filter.hasCategory(Intent.CATEGORY_DEFAULT));
                 if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                     final R oneResult = newResult(filter, match, userId);
+                    if (debug) Slog.v(TAG, "    Created result: " + oneResult);
                     if (oneResult != null) {
                         dest.add(oneResult);
                         if (debug) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 2346cfc..869d564 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -17,9 +17,14 @@
 package com.android.server;
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.NETWORK_PROVIDER;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
 import static android.location.LocationProvider.AVAILABLE;
 import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.Preconditions.checkState;
 
 import android.Manifest;
@@ -29,7 +34,6 @@
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -64,7 +68,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -81,12 +84,14 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
 import com.android.server.location.AbstractLocationProvider;
 import com.android.server.location.ActivityRecognitionProxy;
 import com.android.server.location.GeocoderProxy;
@@ -116,7 +121,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
-import java.util.Set;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -137,16 +141,12 @@
 
     private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
             android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
-    private static final String INSTALL_LOCATION_PROVIDER =
-            android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
 
     private static final String NETWORK_LOCATION_SERVICE_ACTION =
             "com.android.location.service.v3.NetworkLocationProvider";
     private static final String FUSED_LOCATION_SERVICE_ACTION =
             "com.android.location.service.FusedLocationProvider";
 
-    private static final int MSG_LOCATION_CHANGED = 1;
-
     private static final long NANOS_PER_MILLI = 1000000L;
 
     // The maximum interval a location request can have and still be considered "high power".
@@ -170,75 +170,62 @@
 
     private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
 
-    private final Context mContext;
-    private final AppOpsManager mAppOps;
-
-    // used internally for synchronization
     private final Object mLock = new Object();
+    private final Context mContext;
+    private final Handler mHandler;
 
-    // --- fields below are final after systemRunning() ---
-    private LocationFudger mLocationFudger;
-    private GeofenceManager mGeofenceManager;
+    private AppOpsManager mAppOps;
     private PackageManager mPackageManager;
     private PowerManager mPowerManager;
     private ActivityManager mActivityManager;
     private UserManager mUserManager;
+
+    private GeofenceManager mGeofenceManager;
+    private LocationFudger mLocationFudger;
     private GeocoderProxy mGeocodeProvider;
     private GnssStatusListenerHelper mGnssStatusProvider;
     private INetInitiatedListener mNetInitiatedListener;
-    private LocationWorkerHandler mLocationHandler;
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
     private LocationBlacklist mBlacklist;
     private GnssMeasurementsProvider mGnssMeasurementsProvider;
     private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
+    @GuardedBy("mLock")
     private String mLocationControllerExtraPackage;
     private boolean mLocationControllerExtraPackageEnabled;
     private IGpsGeofenceHardware mGpsGeofenceProxy;
 
-    // --- fields below are protected by mLock ---
+    // list of currently active providers
+    @GuardedBy("mLock")
+    private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
 
-    // Mock (test) providers
-    private final HashMap<String, MockProvider> mMockProviders =
-            new HashMap<>();
+    // list of non-mock providers, so that when mock providers replace real providers, they can be
+    // later re-replaced
+    @GuardedBy("mLock")
+    private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
 
-    // all receivers
+    @GuardedBy("mLock")
     private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
-
-    // currently installed providers (with mocks replacing real providers)
-    private final ArrayList<LocationProvider> mProviders =
-            new ArrayList<>();
-
-    // real providers, saved here when mocked out
-    private final HashMap<String, LocationProvider> mRealProviders =
-            new HashMap<>();
-
-    // mapping from provider name to provider
-    private final HashMap<String, LocationProvider> mProvidersByName =
-            new HashMap<>();
-
-    // mapping from provider name to all its UpdateRecords
     private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
             new HashMap<>();
 
     private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
 
     // mapping from provider name to last known location
+    @GuardedBy("mLock")
     private final HashMap<String, Location> mLastLocation = new HashMap<>();
 
     // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
     // locations stored here are not fudged for coarse permissions.
+    @GuardedBy("mLock")
     private final HashMap<String, Location> mLastLocationCoarseInterval =
             new HashMap<>();
 
-    // all providers that operate over proxy, for authorizing incoming location and whitelisting
-    // throttling
-    private final ArrayList<LocationProviderProxy> mProxyProviders =
-            new ArrayList<>();
-
     private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
 
+    @GuardedBy("mLock")
     private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
 
+    @GuardedBy("mLock")
     private final ArrayMap<IBinder, Identity>
             mGnssNavigationMessageListeners = new ArrayMap<>();
 
@@ -246,22 +233,22 @@
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
     private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
 
-    // Maximum age of last location returned to clients with foreground-only location permissions.
-    private long mLastLocationMaxAgeMs;
-
     private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
 
     private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
 
     private GnssBatchingProvider mGnssBatchingProvider;
+    @GuardedBy("mLock")
     private IBatchedLocationCallback mGnssBatchingCallback;
+    @GuardedBy("mLock")
     private LinkedCallback mGnssBatchingDeathCallback;
+    @GuardedBy("mLock")
     private boolean mGnssBatchingInProgress = false;
 
     public LocationManagerService(Context context) {
         super();
         mContext = context;
-        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mHandler = BackgroundThread.getHandler();
 
         // Let the package manager query which are the default location
         // providers as they get certain permissions granted by default.
@@ -271,134 +258,110 @@
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationProviderPackageNames));
 
-        if (D) Log.d(TAG, "Constructed");
-
         // most startup is deferred until systemRunning()
     }
 
     public void systemRunning() {
         synchronized (mLock) {
-            if (D) Log.d(TAG, "systemRunning()");
-
-            // fetch package manager
-            mPackageManager = mContext.getPackageManager();
-
-            // fetch power manager
-            mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-
-            // fetch activity manager
-            mActivityManager
-                    = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-
-            // prepare worker thread
-            mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
-
-            // prepare mLocationHandler's dependents
-            mLocationFudger = new LocationFudger(mContext, mLocationHandler);
-            mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
-            mBlacklist.init();
-            mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
-
-            // Monitor for app ops mode changes.
-            AppOpsManager.OnOpChangedListener callback
-                    = new AppOpsManager.OnOpChangedInternalListener() {
-                public void onOpChanged(int op, String packageName) {
-                            mLocationHandler.post(() -> {
-                                synchronized (mLock) {
-                                    for (Receiver receiver : mReceivers.values()) {
-                                        receiver.updateMonitoring(true);
-                                    }
-                                    applyAllProviderRequirementsLocked();
-                                }
-                            });
-                }
-            };
-            mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
-                    AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
-
-            PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
-                synchronized (mLock) {
-                    applyAllProviderRequirementsLocked();
-                }
-            };
-            mPackageManager.addOnPermissionsChangeListener(permissionListener);
-
-            // listen for background/foreground changes
-            ActivityManager.OnUidImportanceListener uidImportanceListener =
-                    (uid, importance) -> mLocationHandler.post(
-                            () -> onUidImportanceChanged(uid, importance));
-            mActivityManager.addOnUidImportanceListener(uidImportanceListener,
-                    FOREGROUND_IMPORTANCE_CUTOFF);
-
-            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            updateUserProfiles(mCurrentUserId);
-
-            updateBackgroundThrottlingWhitelistLocked();
-            updateLastLocationMaxAgeLocked();
-
-            // prepare providers
-            loadProvidersLocked();
-            updateProvidersSettingsLocked();
-            for (LocationProvider provider : mProviders) {
-                applyRequirementsLocked(provider.getName());
-            }
+            initializeLocked();
         }
+    }
 
-        // listen for settings changes
+    @GuardedBy("mLock")
+    private void initializeLocked() {
+        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mPackageManager = mContext.getPackageManager();
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+        mLocationFudger = new LocationFudger(mContext, mHandler);
+        mBlacklist = new LocationBlacklist(mContext, mHandler);
+        mBlacklist.init();
+        mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
+
+        // prepare providers
+        initializeProvidersLocked();
+
+        // add listeners
+        mAppOps.startWatchingMode(
+                AppOpsManager.OP_COARSE_LOCATION,
+                null,
+                AppOpsManager.WATCH_FOREGROUND_CHANGES,
+                new AppOpsManager.OnOpChangedInternalListener() {
+                    public void onOpChanged(int op, String packageName) {
+                        synchronized (mLock) {
+                            onAppOpChangedLocked();
+                        }
+                    }
+                });
+        mPackageManager.addOnPermissionsChangeListener(
+                uid -> {
+                    synchronized (mLock) {
+                        onPermissionsChangedLocked();
+                    }
+                });
+
+        mActivityManager.addOnUidImportanceListener(
+                (uid, importance) -> {
+                    synchronized (mLock) {
+                        onUidImportanceChangedLocked(uid, importance);
+                    }
+                },
+                FOREGROUND_IMPORTANCE_CUTOFF);
         mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
-                new ContentObserver(mLocationHandler) {
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true,
+                new ContentObserver(mHandler) {
                     @Override
                     public void onChange(boolean selfChange) {
                         synchronized (mLock) {
-                            updateProvidersSettingsLocked();
+                            onLocationModeChangedLocked(true);
+                        }
+                    }
+                }, UserHandle.USER_ALL);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
+                new ContentObserver(mHandler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        synchronized (mLock) {
+                            onProviderAllowedChangedLocked(true);
                         }
                     }
                 }, UserHandle.USER_ALL);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
                 true,
-                new ContentObserver(mLocationHandler) {
+                new ContentObserver(mHandler) {
                     @Override
                     public void onChange(boolean selfChange) {
                         synchronized (mLock) {
-                            for (LocationProvider provider : mProviders) {
-                                applyRequirementsLocked(provider.getName());
-                            }
+                            onBackgroundThrottleIntervalChangedLocked();
                         }
                     }
                 }, UserHandle.USER_ALL);
         mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
-                true,
-                new ContentObserver(mLocationHandler) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        synchronized (mLock) {
-                            updateLastLocationMaxAgeLocked();
-                        }
-                    }
-                }
-        );
-        mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(
                         Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
                 true,
-                new ContentObserver(mLocationHandler) {
+                new ContentObserver(mHandler) {
                     @Override
                     public void onChange(boolean selfChange) {
                         synchronized (mLock) {
-                            updateBackgroundThrottlingWhitelistLocked();
-                            for (LocationProvider provider : mProviders) {
-                                applyRequirementsLocked(provider.getName());
-                            }
+                            onBackgroundThrottleWhitelistChangedLocked();
                         }
                     }
                 }, UserHandle.USER_ALL);
 
-        mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
+        new PackageMonitor() {
+            @Override
+            public void onPackageDisappeared(String packageName, int reason) {
+                synchronized (mLock) {
+                    LocationManagerService.this.onPackageDisappearedLocked(packageName);
+                }
+            }
+        }.register(mContext, mHandler.getLooper(), true);
 
-        // listen for user change
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
         intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
@@ -407,81 +370,152 @@
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
-                        || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
-                    updateUserProfiles(mCurrentUserId);
+                synchronized (mLock) {
+                    String action = intent.getAction();
+                    if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                        onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                    } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
+                            || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+                        onUserProfilesChangedLocked();
+                    }
                 }
             }
-        }, UserHandle.ALL, intentFilter, null, mLocationHandler);
+        }, UserHandle.ALL, intentFilter, null, mHandler);
+
+        // switching the user from null to system here performs the bulk of the initialization work.
+        // the user being changed will cause a reload of all user specific settings, which causes
+        // provider initialization, and propagates changes until a steady state is reached
+        mCurrentUserId = UserHandle.USER_NULL;
+        onUserChangedLocked(UserHandle.USER_SYSTEM);
+
+        // initialize in-memory settings values
+        onBackgroundThrottleWhitelistChangedLocked();
     }
 
-    private void onUidImportanceChanged(int uid, int importance) {
+    @GuardedBy("mLock")
+    private void onAppOpChangedLocked() {
+        for (Receiver receiver : mReceivers.values()) {
+            receiver.updateMonitoring(true);
+        }
+        for (LocationProvider p : mProviders) {
+            applyRequirementsLocked(p);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onPermissionsChangedLocked() {
+        for (LocationProvider p : mProviders) {
+            applyRequirementsLocked(p);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onLocationModeChangedLocked(boolean broadcast) {
+        for (LocationProvider p : mProviders) {
+            p.onLocationModeChangedLocked();
+        }
+
+        if (broadcast) {
+            mContext.sendBroadcastAsUser(
+                    new Intent(LocationManager.MODE_CHANGED_ACTION),
+                    UserHandle.ALL);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onProviderAllowedChangedLocked(boolean broadcast) {
+        for (LocationProvider p : mProviders) {
+            p.onAllowedChangedLocked();
+        }
+
+        if (broadcast) {
+            mContext.sendBroadcastAsUser(
+                    new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
+                    UserHandle.ALL);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onPackageDisappearedLocked(String packageName) {
+        ArrayList<Receiver> deadReceivers = null;
+
+        for (Receiver receiver : mReceivers.values()) {
+            if (receiver.mIdentity.mPackageName.equals(packageName)) {
+                if (deadReceivers == null) {
+                    deadReceivers = new ArrayList<>();
+                }
+                deadReceivers.add(receiver);
+            }
+        }
+
+        // perform removal outside of mReceivers loop
+        if (deadReceivers != null) {
+            for (Receiver receiver : deadReceivers) {
+                removeUpdatesLocked(receiver);
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onUidImportanceChangedLocked(int uid, int importance) {
         boolean foreground = isImportanceForeground(importance);
         HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
-        synchronized (mLock) {
-            for (Entry<String, ArrayList<UpdateRecord>> entry
-                    : mRecordsByProvider.entrySet()) {
-                String provider = entry.getKey();
-                for (UpdateRecord record : entry.getValue()) {
-                    if (record.mReceiver.mIdentity.mUid == uid
-                            && record.mIsForegroundUid != foreground) {
-                        if (D) {
-                            Log.d(TAG, "request from uid " + uid + " is now "
-                                    + (foreground ? "foreground" : "background)"));
-                        }
-                        record.updateForeground(foreground);
-
-                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
-                            affectedProviders.add(provider);
-                        }
-                    }
-                }
-            }
-            for (String provider : affectedProviders) {
-                applyRequirementsLocked(provider);
-            }
-
-            for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
-                Identity callerIdentity = entry.getValue();
-                if (callerIdentity.mUid == uid) {
+        for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
+            String provider = entry.getKey();
+            for (UpdateRecord record : entry.getValue()) {
+                if (record.mReceiver.mIdentity.mUid == uid
+                        && record.mIsForegroundUid != foreground) {
                     if (D) {
-                        Log.d(TAG, "gnss measurements listener from uid " + uid
-                                + " is now " + (foreground ? "foreground" : "background)"));
-                    }
-                    if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                        mGnssMeasurementsProvider.addListener(
-                                IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
-                                callerIdentity.mUid, callerIdentity.mPackageName);
-                    } else {
-                        mGnssMeasurementsProvider.removeListener(
-                                IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
-                    }
-                }
-            }
-
-            for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
-                Identity callerIdentity = entry.getValue();
-                if (callerIdentity.mUid == uid) {
-                    if (D) {
-                        Log.d(TAG, "gnss navigation message listener from uid "
-                                + uid + " is now "
+                        Log.d(TAG, "request from uid " + uid + " is now "
                                 + (foreground ? "foreground" : "background)"));
                     }
-                    if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                        mGnssNavigationMessageProvider.addListener(
-                                IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
-                                callerIdentity.mUid, callerIdentity.mPackageName);
-                    } else {
-                        mGnssNavigationMessageProvider.removeListener(
-                                IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+                    record.updateForeground(foreground);
+
+                    if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
+                        affectedProviders.add(provider);
                     }
                 }
             }
+        }
+        for (String provider : affectedProviders) {
+            applyRequirementsLocked(provider);
+        }
 
-            // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
+        for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
+            Identity callerIdentity = entry.getValue();
+            if (callerIdentity.mUid == uid) {
+                if (D) {
+                    Log.d(TAG, "gnss measurements listener from uid " + uid
+                            + " is now " + (foreground ? "foreground" : "background)"));
+                }
+                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                    mGnssMeasurementsProvider.addListener(
+                            IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
+                            callerIdentity.mUid, callerIdentity.mPackageName);
+                } else {
+                    mGnssMeasurementsProvider.removeListener(
+                            IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
+                }
+            }
+        }
+
+        for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
+            Identity callerIdentity = entry.getValue();
+            if (callerIdentity.mUid == uid) {
+                if (D) {
+                    Log.d(TAG, "gnss navigation message listener from uid "
+                            + uid + " is now "
+                            + (foreground ? "foreground" : "background)"));
+                }
+                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                    mGnssNavigationMessageProvider.addListener(
+                            IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
+                            callerIdentity.mUid, callerIdentity.mPackageName);
+                } else {
+                    mGnssNavigationMessageProvider.removeListener(
+                            IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+                }
+            }
         }
     }
 
@@ -489,30 +523,43 @@
         return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
     }
 
-    /**
-     * Makes a list of userids that are related to the current user. This is
-     * relevant when using managed profiles. Otherwise the list only contains
-     * the current user.
-     *
-     * @param currentUserId the current user, who might have an alter-ego.
-     */
-    private void updateUserProfiles(int currentUserId) {
-        int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
-        synchronized (mLock) {
-            mCurrentUserProfiles = profileIds;
+    @GuardedBy("mLock")
+    private void onBackgroundThrottleIntervalChangedLocked() {
+        for (LocationProvider provider : mProviders) {
+            applyRequirementsLocked(provider);
         }
     }
 
-    /**
-     * Checks if the specified userId matches any of the current foreground
-     * users stored in mCurrentUserProfiles.
-     */
-    private boolean isCurrentProfile(int userId) {
-        synchronized (mLock) {
-            return ArrayUtils.contains(mCurrentUserProfiles, userId);
+    @GuardedBy("mLock")
+    private void onBackgroundThrottleWhitelistChangedLocked() {
+        String setting = Settings.Global.getString(
+                mContext.getContentResolver(),
+                Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+        if (setting == null) {
+            setting = "";
+        }
+
+        mBackgroundThrottlePackageWhitelist.clear();
+        mBackgroundThrottlePackageWhitelist.addAll(
+                SystemConfig.getInstance().getAllowUnthrottledLocation());
+        mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
+
+        for (LocationProvider p : mProviders) {
+            applyRequirementsLocked(p);
         }
     }
 
+    @GuardedBy("mLock")
+    private void onUserProfilesChangedLocked() {
+        mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
+    }
+
+    @GuardedBy("mLock")
+    private boolean isCurrentProfileLocked(int userId) {
+        return ArrayUtils.contains(mCurrentUserProfiles, userId);
+    }
+
+    @GuardedBy("mLock")
     private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
         PackageManager pm = mContext.getPackageManager();
         String systemPackageName = mContext.getPackageName();
@@ -583,30 +630,30 @@
                 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
     }
 
-    private void loadProvidersLocked() {
+    @GuardedBy("mLock")
+    private void initializeProvidersLocked() {
         // create a passive location provider, which is always enabled
-        LocationProvider passiveProviderManager = new LocationProvider(
-                LocationManager.PASSIVE_PROVIDER);
-        PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
-
+        LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
         addProviderLocked(passiveProviderManager);
-        mPassiveProvider = passiveProvider;
+        mPassiveProvider = new PassiveProvider(passiveProviderManager);
+        passiveProviderManager.attachLocked(mPassiveProvider);
 
         if (GnssLocationProvider.isSupported()) {
             // Create a gps location provider
-            LocationProvider gnssProviderManager = new LocationProvider(
-                    LocationManager.GPS_PROVIDER);
+            LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
+            mRealProviders.add(gnssProviderManager);
+            addProviderLocked(gnssProviderManager);
+
             GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
                     gnssProviderManager,
-                    mLocationHandler.getLooper());
+                    mHandler.getLooper());
+            gnssProviderManager.attachLocked(gnssProvider);
 
             mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
             mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
             mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
             mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
             mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
-            addProviderLocked(gnssProviderManager);
-            mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
             mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
             mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
             mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
@@ -634,9 +681,7 @@
         ensureFallbackFusedProviderPresentLocked(pkgs);
 
         // bind to network provider
-
-        LocationProvider networkProviderManager = new LocationProvider(
-                LocationManager.NETWORK_PROVIDER);
+        LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
         LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
                 mContext,
                 networkProviderManager,
@@ -645,16 +690,15 @@
                 com.android.internal.R.string.config_networkLocationProviderPackageName,
                 com.android.internal.R.array.config_locationProviderPackageNames);
         if (networkProvider != null) {
-            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
-            mProxyProviders.add(networkProvider);
+            mRealProviders.add(networkProviderManager);
             addProviderLocked(networkProviderManager);
+            networkProviderManager.attachLocked(networkProvider);
         } else {
             Slog.w(TAG, "no network location provider found");
         }
 
         // bind to fused provider
-        LocationProvider fusedProviderManager = new LocationProvider(
-                LocationManager.FUSED_PROVIDER);
+        LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
         LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
                 mContext,
                 fusedProviderManager,
@@ -663,9 +707,9 @@
                 com.android.internal.R.string.config_fusedLocationProviderPackageName,
                 com.android.internal.R.array.config_locationProviderPackageNames);
         if (fusedProvider != null) {
+            mRealProviders.add(fusedProviderManager);
             addProviderLocked(fusedProviderManager);
-            mProxyProviders.add(fusedProvider);
-            mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
+            fusedProviderManager.attachLocked(fusedProvider);
         } else {
             Slog.e(TAG, "no fused location provider found",
                     new IllegalStateException("Location service needs a fused location provider"));
@@ -715,9 +759,6 @@
         for (String testProviderString : testProviderStrings) {
             String fragments[] = testProviderString.split(",");
             String name = fragments[0].trim();
-            if (mProvidersByName.get(name) != null) {
-                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
-            }
             ProviderProperties properties = new ProviderProperties(
                     Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
                     Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
@@ -728,28 +769,37 @@
                     Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
                     Integer.parseInt(fragments[8]) /* powerRequirement */,
                     Integer.parseInt(fragments[9]) /* accuracy */);
-            addTestProviderLocked(name, properties);
+            LocationProvider testProviderManager = new LocationProvider(name);
+            addProviderLocked(testProviderManager);
+            new MockProvider(testProviderManager, properties);
         }
     }
 
-    /**
-     * Called when the device's active user changes.
-     *
-     * @param userId the new active user's UserId
-     */
-    private void switchUser(int userId) {
+    @GuardedBy("mLock")
+    private void onUserChangedLocked(int userId) {
         if (mCurrentUserId == userId) {
             return;
         }
-        mBlacklist.switchUser(userId);
-        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
-        synchronized (mLock) {
-            mLastLocation.clear();
-            mLastLocationCoarseInterval.clear();
-            updateUserProfiles(userId);
-            updateProvidersSettingsLocked();
-            mCurrentUserId = userId;
+
+        // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
+        // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
+        // will see it in an appropriate state (at least after that user becomes foreground for the
+        // first time...)
+        isLocationEnabledForUser(userId);
+
+        // let providers know the current user is on the way out before changing the user
+        for (LocationProvider p : mProviders) {
+            p.onUserChangingLocked();
         }
+
+        mCurrentUserId = userId;
+        onUserProfilesChangedLocked();
+
+        mBlacklist.switchUser(userId);
+
+        // if the user changes, per-user settings may also have changed
+        onLocationModeChangedLocked(false);
+        onProviderAllowedChangedLocked(false);
     }
 
     private static final class Identity {
@@ -767,158 +817,380 @@
     private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
 
         private final String mName;
-        private AbstractLocationProvider mProvider;
 
-        // whether the provider is enabled in location settings
-        private boolean mSettingsEnabled;
+        // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
+        private final boolean mIsManagedBySettings;
 
-        // whether the provider considers itself enabled
-        private volatile boolean mEnabled;
+        // remember to clear binder identity before invoking any provider operation
+        @GuardedBy("mLock")
+        @Nullable protected AbstractLocationProvider mProvider;
 
-        @Nullable
-        private volatile ProviderProperties mProperties;
+        @GuardedBy("mLock")
+        private boolean mUseable;  // combined state
+        @GuardedBy("mLock")
+        private boolean mAllowed;  // state of LOCATION_PROVIDERS_ALLOWED
+        @GuardedBy("mLock")
+        private boolean mEnabled;  // state of provider
+
+        @GuardedBy("mLock")
+        @Nullable private ProviderProperties mProperties;
 
         private LocationProvider(String name) {
-            mName = name;
-            // TODO: initialize settings enabled?
+            this(name, false);
         }
 
-        @Override
-        public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
-            checkState(mProvider == null);
+        private LocationProvider(String name, boolean isManagedBySettings) {
+            mName = name;
+            mIsManagedBySettings = isManagedBySettings;
 
-            // the provider is not yet fully constructed at this point, so we may not do anything
-            // except save a reference for later use here. do not call any provider methods.
-            mProvider = provider;
-            mEnabled = initiallyEnabled;
+            mProvider = null;
+            mUseable = false;
+            mAllowed = !mIsManagedBySettings;
+            mEnabled = false;
             mProperties = null;
         }
 
+        @GuardedBy("mLock")
+        public void attachLocked(AbstractLocationProvider provider) {
+            checkNotNull(provider);
+            checkState(mProvider == null);
+            mProvider = provider;
+
+            onUseableChangedLocked();
+        }
+
         public String getName() {
             return mName;
         }
 
-        public boolean isEnabled() {
-            return mSettingsEnabled && mEnabled;
+        @GuardedBy("mLock")
+        @Nullable
+        public String getPackageLocked() {
+            if (mProvider == null) {
+                return null;
+            } else if (mProvider instanceof LocationProviderProxy) {
+                // safe to not clear binder context since this doesn't call into the actual provider
+                return ((LocationProviderProxy) mProvider).getConnectedPackageName();
+            } else {
+                return mContext.getPackageName();
+            }
         }
 
+        public boolean isMock() {
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        public boolean isPassiveLocked() {
+            return mProvider == mPassiveProvider;
+        }
+
+        @GuardedBy("mLock")
         @Nullable
-        public ProviderProperties getProperties() {
+        public ProviderProperties getPropertiesLocked() {
             return mProperties;
         }
 
-        public void setRequest(ProviderRequest request, WorkSource workSource) {
-            mProvider.setRequest(request, workSource);
+        @GuardedBy("mLock")
+        public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mProvider.setRequest(request, workSource);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
         }
 
-        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        @GuardedBy("mLock")
+        public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
             pw.println(mName + " provider:");
-            pw.println(" setting=" + mSettingsEnabled);
+            if (isMock()) {
+                pw.println(" mock=true");
+            }
+            pw.println(" attached=" + (mProvider != null));
+            if (mIsManagedBySettings) {
+                pw.println(" allowed=" + mAllowed);
+            }
             pw.println(" enabled=" + mEnabled);
+            pw.println(" useable=" + mUseable);
             pw.println(" properties=" + mProperties);
-            mProvider.dump(fd, pw, args);
+
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mProvider.dump(fd, pw, args);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
         }
 
-        public long getStatusUpdateTime() {
-            return mProvider.getStatusUpdateTime();
+        @GuardedBy("mLock")
+        public long getStatusUpdateTimeLocked() {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    return mProvider.getStatusUpdateTime();
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            } else {
+                return 0;
+            }
         }
 
-        public int getStatus(Bundle extras) {
-            return mProvider.getStatus(extras);
+        @GuardedBy("mLock")
+        public int getStatusLocked(Bundle extras) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    return mProvider.getStatus(extras);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            } else {
+                return AVAILABLE;
+            }
         }
 
-        public void sendExtraCommand(String command, Bundle extras) {
-            mProvider.sendExtraCommand(command, extras);
+        @GuardedBy("mLock")
+        public void sendExtraCommandLocked(String command, Bundle extras) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mProvider.sendExtraCommand(command, extras);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
         }
 
         // called from any thread
         @Override
         public void onReportLocation(Location location) {
-            runOnHandler(() -> LocationManagerService.this.reportLocation(location,
-                    mProvider == mPassiveProvider));
+            // no security check necessary because this is coming from an internal-only interface
+            // move calls coming from below LMS onto a different thread to avoid deadlock
+            runInternal(() -> {
+                synchronized (mLock) {
+                    handleLocationChangedLocked(location, this);
+                }
+            });
         }
 
         // called from any thread
         @Override
         public void onReportLocation(List<Location> locations) {
-            runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
+            // move calls coming from below LMS onto a different thread to avoid deadlock
+            runInternal(() -> {
+                synchronized (mLock) {
+                    LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
+                    if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
+                        Slog.w(TAG, "reportLocationBatch() called without user permission");
+                        return;
+                    }
+
+                    if (mGnssBatchingCallback == null) {
+                        Slog.e(TAG, "reportLocationBatch() called without active Callback");
+                        return;
+                    }
+
+                    try {
+                        mGnssBatchingCallback.onLocationBatch(locations);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
+                    }
+                }
+            });
         }
 
         // called from any thread
         @Override
         public void onSetEnabled(boolean enabled) {
-            runOnHandler(() -> {
-                if (enabled == mEnabled) {
-                    return;
-                }
-
-                mEnabled = enabled;
-
-                if (!mSettingsEnabled) {
-                    // this provider was disabled in settings anyways, so a change to it's own
-                    // enabled status won't have any affect.
-                    return;
-                }
-
-                // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
-                // setting to detect when providers are enabled or disabled (even though they aren't
-                // supposed to). to continue to support this we must force a change to this setting.
-                // we use the fused provider because this is forced to be always enabled in settings
-                // anyways, and so won't have any visible effect beyond triggering content observers
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
-
+            // move calls coming from below LMS onto a different thread to avoid deadlock
+            runInternal(() -> {
                 synchronized (mLock) {
-                    if (!enabled) {
-                        // If any provider has been disabled, clear all last locations for all
-                        // providers. This is to be on the safe side in case a provider has location
-                        // derived from this disabled provider.
-                        mLastLocation.clear();
-                        mLastLocationCoarseInterval.clear();
+                    if (enabled == mEnabled) {
+                        return;
                     }
 
-                    updateProviderListenersLocked(mName);
-                }
+                    mEnabled = enabled;
 
-                mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
-                        UserHandle.ALL);
+                    // update provider allowed settings to reflect enabled status
+                    if (mIsManagedBySettings) {
+                        if (mEnabled && !mAllowed) {
+                            Settings.Secure.putStringForUser(
+                                    mContext.getContentResolver(),
+                                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                                    "+" + mName,
+                                    mCurrentUserId);
+                        } else if (!mEnabled && mAllowed) {
+                            Settings.Secure.putStringForUser(
+                                    mContext.getContentResolver(),
+                                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                                    "-" + mName,
+                                    mCurrentUserId);
+                        }
+                    }
+
+                    onUseableChangedLocked();
+                }
             });
         }
 
         @Override
         public void onSetProperties(ProviderProperties properties) {
-            runOnHandler(() -> mProperties = properties);
+            // move calls coming from below LMS onto a different thread to avoid deadlock
+            runInternal(() -> {
+                synchronized (mLock) {
+                    mProperties = properties;
+                }
+            });
         }
 
-        private void setSettingsEnabled(boolean enabled) {
-            synchronized (mLock) {
-                if (mSettingsEnabled == enabled) {
+        @GuardedBy("mLock")
+        public void onLocationModeChangedLocked() {
+            onUseableChangedLocked();
+        }
+
+        private boolean isAllowed() {
+            return isAllowedForUser(mCurrentUserId);
+        }
+
+        private boolean isAllowedForUser(int userId) {
+            String allowedProviders = Settings.Secure.getStringForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                    userId);
+            return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
+        }
+
+        @GuardedBy("mLock")
+        public void onAllowedChangedLocked() {
+            if (mIsManagedBySettings) {
+                boolean allowed = isAllowed();
+                if (allowed == mAllowed) {
                     return;
                 }
+                mAllowed = allowed;
 
-                mSettingsEnabled = enabled;
-                if (!mSettingsEnabled) {
-                    // if any provider has been disabled, clear all last locations for all
-                    // providers. this is to be on the safe side in case a provider has location
-                    // derived from this disabled provider.
-                    mLastLocation.clear();
-                    mLastLocationCoarseInterval.clear();
-                    updateProviderListenersLocked(mName);
-                } else if (mEnabled) {
-                    updateProviderListenersLocked(mName);
+                // make a best effort to keep the setting matching the real enabled state of the
+                // provider so that legacy applications aren't broken.
+                if (mAllowed && !mEnabled) {
+                    Settings.Secure.putStringForUser(
+                            mContext.getContentResolver(),
+                            Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                            "-" + mName,
+                            mCurrentUserId);
+                }
+
+                onUseableChangedLocked();
+            }
+        }
+
+        @GuardedBy("mLock")
+        public boolean isUseableLocked() {
+            return isUseableForUserLocked(mCurrentUserId);
+        }
+
+        @GuardedBy("mLock")
+        public boolean isUseableForUserLocked(int userId) {
+            return userId == mCurrentUserId && mUseable;
+        }
+
+        @GuardedBy("mLock")
+        public void onUseableChangedLocked() {
+            // if any property that contributes to "useability" here changes state, it MUST result
+            // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
+            // guarantee that it will always eventually reach the correct state.
+            boolean useable = mProvider != null
+                    && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
+            if (useable == mUseable) {
+                return;
+            }
+            mUseable = useable;
+
+            if (!mUseable) {
+                // If any provider has been disabled, clear all last locations for all
+                // providers. This is to be on the safe side in case a provider has location
+                // derived from this disabled provider.
+                mLastLocation.clear();
+                mLastLocationCoarseInterval.clear();
+            }
+
+            updateProviderUseableLocked(this);
+        }
+
+        @GuardedBy("mLock")
+        public void onUserChangingLocked() {
+            // when the user is about to change, we set this provider to un-useable, and notify all
+            // of the current user clients. when the user is finished changing, useability will be
+            // updated back via onLocationModeChanged() and onAllowedChanged().
+            mUseable = false;
+            updateProviderUseableLocked(this);
+        }
+
+        // binder transactions coming from below LMS (ie location providers) need to be moved onto
+        // a different thread to avoid potential deadlock as code reenters the location providers
+        private void runInternal(Runnable runnable) {
+            if (Looper.myLooper() == mHandler.getLooper()) {
+                runnable.run();
+            } else {
+                mHandler.post(runnable);
+            }
+        }
+    }
+
+    private class MockLocationProvider extends LocationProvider {
+
+        private MockLocationProvider(String name) {
+            super(name);
+        }
+
+        @Override
+        public void attachLocked(AbstractLocationProvider provider) {
+            checkState(provider instanceof MockProvider);
+            super.attachLocked(provider);
+        }
+
+        public boolean isMock() {
+            return true;
+        }
+
+        @GuardedBy("mLock")
+        public void setEnabledLocked(boolean enabled) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    ((MockProvider) mProvider).setEnabled(enabled);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
                 }
             }
         }
 
-        private void runOnHandler(Runnable runnable) {
-            if (Looper.myLooper() == mLocationHandler.getLooper()) {
-                runnable.run();
-            } else {
-                mLocationHandler.post(runnable);
+        @GuardedBy("mLock")
+        public void setLocationLocked(Location location) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    ((MockProvider) mProvider).setLocation(location);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        public void setStatusLocked(int status, Bundle extras, long updateTime) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    ((MockProvider) mProvider).setStatus(status, extras, updateTime);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
             }
         }
     }
@@ -1022,19 +1294,18 @@
                 // See if receiver has any enabled update records.  Also note if any update records
                 // are high power (has a high power provider with an interval under a threshold).
                 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
-                    if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
-                            mCurrentUserId)) {
-                        requestingLocation = true;
-                        LocationManagerService.LocationProvider locationProvider
-                                = mProvidersByName.get(updateRecord.mProvider);
-                        ProviderProperties properties = locationProvider != null
-                                ? locationProvider.getProperties() : null;
-                        if (properties != null
-                                && properties.mPowerRequirement == Criteria.POWER_HIGH
-                                && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
-                            requestingHighPowerLocation = true;
-                            break;
-                        }
+                    LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
+                    if (provider == null || !provider.isUseableLocked()) {
+                        continue;
+                    }
+
+                    requestingLocation = true;
+                    ProviderProperties properties = provider.getPropertiesLocked();
+                    if (properties != null
+                            && properties.mPowerRequirement == Criteria.POWER_HIGH
+                            && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
+                        requestingHighPowerLocation = true;
+                        break;
                     }
                 }
             }
@@ -1122,7 +1393,7 @@
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
+                        mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
                                 getResolutionPermission(mAllowedResolutionLevel),
                                 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
                         // call this after broadcasting so we do not increment
@@ -1158,7 +1429,7 @@
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
+                        mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
                                 getResolutionPermission(mAllowedResolutionLevel),
                                 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
                         // call this after broadcasting so we do not increment
@@ -1201,7 +1472,7 @@
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
+                        mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
                                 getResolutionPermission(mAllowedResolutionLevel),
                                 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
                         // call this after broadcasting so we do not increment
@@ -1273,16 +1544,16 @@
                 synchronized (receiver) {
                     // so wakelock calls will succeed
                     long identity = Binder.clearCallingIdentity();
-                    receiver.decrementPendingBroadcastsLocked();
-                    Binder.restoreCallingIdentity(identity);
+                    try {
+                        receiver.decrementPendingBroadcastsLocked();
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
                 }
             }
         }
     }
 
-    /**
-     * Returns the year of the GNSS hardware.
-     */
     @Override
     public int getGnssYearOfHardware() {
         if (mGnssSystemInfoProvider != null) {
@@ -1292,10 +1563,6 @@
         }
     }
 
-
-    /**
-     * Returns the model name of the GNSS hardware.
-     */
     @Override
     @Nullable
     public String getGnssHardwareModelName() {
@@ -1306,32 +1573,24 @@
         }
     }
 
-    /**
-     * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
-     * (try to) access GNSS information at this layer.
-     */
     private boolean hasGnssPermissions(String packageName) {
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkResolutionLevelIsSufficientForProviderUse(
-                allowedResolutionLevel,
-                LocationManager.GPS_PROVIDER);
+        synchronized (mLock) {
+            int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+            checkResolutionLevelIsSufficientForProviderUseLocked(
+                    allowedResolutionLevel,
+                    GPS_PROVIDER);
 
-        int pid = Binder.getCallingPid();
-        int uid = Binder.getCallingUid();
-        long identity = Binder.clearCallingIdentity();
-        boolean hasLocationAccess;
-        try {
-            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            int pid = Binder.getCallingPid();
+            int uid = Binder.getCallingUid();
+            long identity = Binder.clearCallingIdentity();
+            try {
+                return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
-
-        return hasLocationAccess;
     }
 
-    /**
-     * Returns the GNSS batching size, if available.
-     */
     @Override
     public int getGnssBatchSize(String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1344,10 +1603,6 @@
         }
     }
 
-    /**
-     * Adds a callback for GNSS Batching events, if permissions allow, which are transported
-     * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
-     */
     @Override
     public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1357,18 +1612,20 @@
             return false;
         }
 
-        mGnssBatchingCallback = callback;
-        mGnssBatchingDeathCallback = new LinkedCallback(callback);
-        try {
-            callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
-        } catch (RemoteException e) {
-            // if the remote process registering the listener is already dead, just swallow the
-            // exception and return
-            Log.e(TAG, "Remote listener already died.", e);
-            return false;
-        }
+        synchronized (mLock) {
+            mGnssBatchingCallback = callback;
+            mGnssBatchingDeathCallback = new LinkedCallback(callback);
+            try {
+                callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
+            } catch (RemoteException e) {
+                // if the remote process registering the listener is already dead, just swallow the
+                // exception and return
+                Log.e(TAG, "Remote listener already died.", e);
+                return false;
+            }
 
-        return true;
+            return true;
+        }
     }
 
     private class LinkedCallback implements IBinder.DeathRecipient {
@@ -1391,27 +1648,22 @@
         }
     }
 
-    /**
-     * Removes callback for GNSS batching
-     */
     @Override
     public void removeGnssBatchingCallback() {
-        try {
-            mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
-                    0 /* flags */);
-        } catch (NoSuchElementException e) {
-            // if the death callback isn't connected (it should be...), log error, swallow the
-            // exception and return
-            Log.e(TAG, "Couldn't unlink death callback.", e);
+        synchronized (mLock) {
+            try {
+                mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
+                        0 /* flags */);
+            } catch (NoSuchElementException e) {
+                // if the death callback isn't connected (it should be...), log error, swallow the
+                // exception and return
+                Log.e(TAG, "Couldn't unlink death callback.", e);
+            }
+            mGnssBatchingCallback = null;
+            mGnssBatchingDeathCallback = null;
         }
-        mGnssBatchingCallback = null;
-        mGnssBatchingDeathCallback = null;
     }
 
-
-    /**
-     * Starts GNSS batching, if available.
-     */
     @Override
     public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1421,20 +1673,20 @@
             return false;
         }
 
-        if (mGnssBatchingInProgress) {
-            // Current design does not expect multiple starts to be called repeatedly
-            Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
-            // Try to clean up anyway, and continue
-            stopGnssBatch();
-        }
+        synchronized (mLock) {
+            if (mGnssBatchingInProgress) {
+                // Current design does not expect multiple starts to be called repeatedly
+                Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
+                // Try to clean up anyway, and continue
+                stopGnssBatch();
+            }
 
-        mGnssBatchingInProgress = true;
-        return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
+            mGnssBatchingInProgress = true;
+            return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
+        }
     }
 
-    /**
-     * Flushes a GNSS batch in progress
-     */
+
     @Override
     public void flushGnssBatch(String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1445,117 +1697,66 @@
             return;
         }
 
-        if (!mGnssBatchingInProgress) {
-            Log.w(TAG, "flushGnssBatch called with no batch in progress");
-        }
+        synchronized (mLock) {
+            if (!mGnssBatchingInProgress) {
+                Log.w(TAG, "flushGnssBatch called with no batch in progress");
+            }
 
-        if (mGnssBatchingProvider != null) {
-            mGnssBatchingProvider.flush();
+            if (mGnssBatchingProvider != null) {
+                mGnssBatchingProvider.flush();
+            }
         }
     }
 
-    /**
-     * Stops GNSS batching
-     */
     @Override
     public boolean stopGnssBatch() {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to access hardware batching");
 
-        if (mGnssBatchingProvider != null) {
-            mGnssBatchingInProgress = false;
-            return mGnssBatchingProvider.stop();
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public void reportLocationBatch(List<Location> locations) {
-        checkCallerIsProvider();
-
-        // Currently used only for GNSS locations - update permissions check if changed
-        if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
-            if (mGnssBatchingCallback == null) {
-                Slog.e(TAG, "reportLocationBatch() called without active Callback");
-                return;
-            }
-            try {
-                mGnssBatchingCallback.onLocationBatch(locations);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
-            }
-        } else {
-            Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
-        }
-    }
-
-    private void addProviderLocked(LocationProvider provider) {
-        mProviders.add(provider);
-        mProvidersByName.put(provider.getName(), provider);
-    }
-
-    private void removeProviderLocked(LocationProvider provider) {
-        mProviders.remove(provider);
-        mProvidersByName.remove(provider.getName());
-    }
-
-    /**
-     * Returns "true" if access to the specified location provider is allowed by the specified
-     * user's settings. Access to all location providers is forbidden to non-location-provider
-     * processes belonging to background users.
-     *
-     * @param provider the name of the location provider
-     * @param userId   the user id to query
-     */
-    private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
-        if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
-            return isLocationEnabledForUser(userId);
-        }
-        if (LocationManager.FUSED_PROVIDER.equals(provider)) {
-            return isLocationEnabledForUser(userId);
-        }
         synchronized (mLock) {
-            if (mMockProviders.containsKey(provider)) {
-                return isLocationEnabledForUser(userId);
+            if (mGnssBatchingProvider != null) {
+                mGnssBatchingInProgress = false;
+                return mGnssBatchingProvider.stop();
+            } else {
+                return false;
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void addProviderLocked(LocationProvider provider) {
+        Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
+
+        mProviders.add(provider);
+
+        provider.onAllowedChangedLocked();  // allowed state may change while provider was inactive
+        provider.onUseableChangedLocked();
+    }
+
+    @GuardedBy("mLock")
+    private void removeProviderLocked(LocationProvider provider) {
+        if (mProviders.remove(provider)) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                provider.onUseableChangedLocked();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private LocationProvider getLocationProviderLocked(String providerName) {
+        for (LocationProvider provider : mProviders) {
+            if (providerName.equals(provider.getName())) {
+                return provider;
             }
         }
 
-        long identity = Binder.clearCallingIdentity();
-        try {
-            // Use system settings
-            ContentResolver cr = mContext.getContentResolver();
-            String allowedProviders = Settings.Secure.getStringForUser(
-                    cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
-            return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+        return null;
     }
 
-
-    /**
-     * Returns "true" if access to the specified location provider is allowed by the specified
-     * user's settings. Access to all location providers is forbidden to non-location-provider
-     * processes belonging to background users.
-     *
-     * @param provider the name of the location provider
-     * @param uid      the requestor's UID
-     * @param userId   the user id to query
-     */
-    private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
-        if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
-            return false;
-        }
-        return isAllowedByUserSettingsLockedForUser(provider, userId);
-    }
-
-    /**
-     * Returns the permission string associated with the specified resolution level.
-     *
-     * @param resolutionLevel the resolution level
-     * @return the permission string
-     */
     private String getResolutionPermission(int resolutionLevel) {
         switch (resolutionLevel) {
             case RESOLUTION_LEVEL_FINE:
@@ -1567,13 +1768,6 @@
         }
     }
 
-    /**
-     * Returns the resolution level allowed to the given PID/UID pair.
-     *
-     * @param pid the PID
-     * @param uid the UID
-     * @return resolution level allowed to the pid/uid pair
-     */
     private int getAllowedResolutionLevel(int pid, int uid) {
         if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
                 pid, uid) == PERMISSION_GRANTED) {
@@ -1586,39 +1780,22 @@
         }
     }
 
-    /**
-     * Returns the resolution level allowed to the caller
-     *
-     * @return resolution level allowed to caller
-     */
     private int getCallerAllowedResolutionLevel() {
         return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
     }
 
-    /**
-     * Throw SecurityException if specified resolution level is insufficient to use geofences.
-     *
-     * @param allowedResolutionLevel resolution level allowed to caller
-     */
     private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
         if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
             throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
         }
     }
 
-    /**
-     * Return the minimum resolution level required to use the specified location provider.
-     *
-     * @param provider the name of the location provider
-     * @return minimum resolution level required for provider
-     */
-    private int getMinimumResolutionLevelForProviderUse(String provider) {
-        if (LocationManager.GPS_PROVIDER.equals(provider) ||
-                LocationManager.PASSIVE_PROVIDER.equals(provider)) {
+    @GuardedBy("mLock")
+    private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
+        if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
             // gps and passive providers require FINE permission
             return RESOLUTION_LEVEL_FINE;
-        } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
-                LocationManager.FUSED_PROVIDER.equals(provider)) {
+        } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
             // network and fused providers are ok with COARSE or FINE
             return RESOLUTION_LEVEL_COARSE;
         } else {
@@ -1627,7 +1804,7 @@
                     continue;
                 }
 
-                ProviderProperties properties = lp.getProperties();
+                ProviderProperties properties = lp.getPropertiesLocked();
                 if (properties != null) {
                     if (properties.mRequiresSatellite) {
                         // provider requiring satellites require FINE permission
@@ -1643,16 +1820,10 @@
         return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
     }
 
-    /**
-     * Throw SecurityException if specified resolution level is insufficient to use the named
-     * location provider.
-     *
-     * @param allowedResolutionLevel resolution level allowed to caller
-     * @param providerName           the name of the location provider
-     */
-    private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
+    @GuardedBy("mLock")
+    private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
             String providerName) {
-        int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
+        int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
         if (allowedResolutionLevel < requiredResolutionLevel) {
             switch (requiredResolutionLevel) {
                 case RESOLUTION_LEVEL_FINE:
@@ -1668,20 +1839,6 @@
         }
     }
 
-    /**
-     * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
-     * for battery).
-     */
-    private void checkDeviceStatsAllowed() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_DEVICE_STATS, null);
-    }
-
-    private void checkUpdateAppOpsAllowed() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
-    }
-
     public static int resolutionLevelToOp(int allowedResolutionLevel) {
         if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
             if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1739,19 +1896,17 @@
      */
     @Override
     public List<String> getAllProviders() {
-        ArrayList<String> out;
         synchronized (mLock) {
-            out = new ArrayList<>(mProviders.size());
+            ArrayList<String> providers = new ArrayList<>(mProviders.size());
             for (LocationProvider provider : mProviders) {
                 String name = provider.getName();
-                if (LocationManager.FUSED_PROVIDER.equals(name)) {
+                if (FUSED_PROVIDER.equals(name)) {
                     continue;
                 }
-                out.add(name);
+                providers.add(name);
             }
+            return providers;
         }
-        if (D) Log.d(TAG, "getAllProviders()=" + out);
-        return out;
     }
 
     /**
@@ -1762,37 +1917,28 @@
     @Override
     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        ArrayList<String> out;
-        int uid = Binder.getCallingUid();
-        long identity = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                out = new ArrayList<>(mProviders.size());
-                for (LocationProvider provider : mProviders) {
-                    String name = provider.getName();
-                    if (LocationManager.FUSED_PROVIDER.equals(name)) {
-                        continue;
-                    }
-                    if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
-                        if (enabledOnly
-                                && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
-                            continue;
-                        }
-                        if (criteria != null
-                                && !android.location.LocationProvider.propertiesMeetCriteria(
-                                name, provider.getProperties(), criteria)) {
-                            continue;
-                        }
-                        out.add(name);
-                    }
+        synchronized (mLock) {
+            ArrayList<String> providers = new ArrayList<>(mProviders.size());
+            for (LocationProvider provider : mProviders) {
+                String name = provider.getName();
+                if (FUSED_PROVIDER.equals(name)) {
+                    continue;
                 }
+                if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
+                    continue;
+                }
+                if (enabledOnly && !provider.isUseableLocked()) {
+                    continue;
+                }
+                if (criteria != null
+                        && !android.location.LocationProvider.propertiesMeetCriteria(
+                        name, provider.getPropertiesLocked(), criteria)) {
+                    continue;
+                }
+                providers.add(name);
             }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            return providers;
         }
-
-        if (D) Log.d(TAG, "getProviders()=" + out);
-        return out;
     }
 
     /**
@@ -1804,71 +1950,36 @@
      */
     @Override
     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
-        String result;
-
         List<String> providers = getProviders(criteria, enabledOnly);
-        if (!providers.isEmpty()) {
-            result = pickBest(providers);
-            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
-            return result;
-        }
-        providers = getProviders(null, enabledOnly);
-        if (!providers.isEmpty()) {
-            result = pickBest(providers);
-            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
-            return result;
+        if (providers.isEmpty()) {
+            providers = getProviders(null, enabledOnly);
         }
 
-        if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
+        if (!providers.isEmpty()) {
+            if (providers.contains(GPS_PROVIDER)) {
+                return GPS_PROVIDER;
+            } else if (providers.contains(NETWORK_PROVIDER)) {
+                return NETWORK_PROVIDER;
+            } else {
+                return providers.get(0);
+            }
+        }
+
         return null;
     }
 
-    private String pickBest(List<String> providers) {
-        if (providers.contains(LocationManager.GPS_PROVIDER)) {
-            return LocationManager.GPS_PROVIDER;
-        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
-            return LocationManager.NETWORK_PROVIDER;
-        } else {
-            return providers.get(0);
-        }
-    }
-
-    @Override
-    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) {
-            throw new IllegalArgumentException("provider=" + provider);
-        }
-
-        boolean result = android.location.LocationProvider.propertiesMeetCriteria(
-                p.getName(), p.getProperties(), criteria);
-        if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
-        return result;
-    }
-
-    private void updateProvidersSettingsLocked() {
-        for (LocationProvider p : mProviders) {
-            p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
-        }
-
-        mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
-                UserHandle.ALL);
-    }
-
-    private void updateProviderListenersLocked(String provider) {
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) return;
-
-        boolean enabled = p.isEnabled();
+    @GuardedBy("mLock")
+    private void updateProviderUseableLocked(LocationProvider provider) {
+        boolean useable = provider.isUseableLocked();
 
         ArrayList<Receiver> deadReceivers = null;
 
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
+                if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                     // Sends a notification message to the receiver
-                    if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
+                    if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
                         if (deadReceivers == null) {
                             deadReceivers = new ArrayList<>();
                         }
@@ -1887,25 +1998,37 @@
         applyRequirementsLocked(provider);
     }
 
-    private void applyRequirementsLocked(String provider) {
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) return;
+    @GuardedBy("mLock")
+    private void applyRequirementsLocked(String providerName) {
+        LocationProvider provider = getLocationProviderLocked(providerName);
+        if (provider != null) {
+            applyRequirementsLocked(provider);
+        }
+    }
 
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+    @GuardedBy("mLock")
+    private void applyRequirementsLocked(LocationProvider provider) {
+        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
         WorkSource worksource = new WorkSource();
         ProviderRequest providerRequest = new ProviderRequest();
 
-        ContentResolver resolver = mContext.getContentResolver();
-        long backgroundThrottleInterval = Settings.Global.getLong(
-                resolver,
-                Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
-                DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+        long backgroundThrottleInterval;
 
-        if (p.isEnabled() && records != null && !records.isEmpty()) {
+        long identity = Binder.clearCallingIdentity();
+        try {
+            backgroundThrottleInterval = Settings.Global.getLong(
+                    mContext.getContentResolver(),
+                    Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
+                    DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        if (provider.isUseableLocked() && records != null && !records.isEmpty()) {
             // initialize the low power mode to true and set to false if any of the records requires
             providerRequest.lowPowerMode = true;
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
+                if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                     if (checkLocationAccess(
                             record.mReceiver.mIdentity.mPid,
                             record.mReceiver.mIdentity.mUid,
@@ -1945,7 +2068,8 @@
                 // under that threshold.
                 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
                 for (UpdateRecord record : records) {
-                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
+                    if (isCurrentProfileLocked(
+                            UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                         LocationRequest locationRequest = record.mRequest;
 
                         // Don't assign battery blame for update records whose
@@ -1972,7 +2096,7 @@
         }
 
         if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
-        p.setRequest(providerRequest, worksource);
+        provider.setRequestLocked(providerRequest, worksource);
     }
 
     /**
@@ -1995,34 +2119,11 @@
     @Override
     public String[] getBackgroundThrottlingWhitelist() {
         synchronized (mLock) {
-            return mBackgroundThrottlePackageWhitelist.toArray(
-                    new String[0]);
+            return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
         }
     }
 
-    private void updateBackgroundThrottlingWhitelistLocked() {
-        String setting = Settings.Global.getString(
-                mContext.getContentResolver(),
-                Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
-        if (setting == null) {
-            setting = "";
-        }
-
-        mBackgroundThrottlePackageWhitelist.clear();
-        mBackgroundThrottlePackageWhitelist.addAll(
-                SystemConfig.getInstance().getAllowUnthrottledLocation());
-        mBackgroundThrottlePackageWhitelist.addAll(
-                Arrays.asList(setting.split(",")));
-    }
-
-    private void updateLastLocationMaxAgeLocked() {
-        mLastLocationMaxAgeMs =
-                Settings.Global.getLong(
-                        mContext.getContentResolver(),
-                        Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
-                        DEFAULT_LAST_LOCATION_MAX_AGE_MS);
-    }
-
+    @GuardedBy("mLock")
     private boolean isThrottlingExemptLocked(Identity identity) {
         if (identity.mUid == Process.SYSTEM_UID) {
             return true;
@@ -2032,8 +2133,8 @@
             return true;
         }
 
-        for (LocationProviderProxy provider : mProxyProviders) {
-            if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
+        for (LocationProvider provider : mProviders) {
+            if (identity.mPackageName.equals(provider.getPackageLocked())) {
                 return true;
             }
         }
@@ -2119,6 +2220,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
             String packageName, WorkSource workSource, boolean hideFromAppOps) {
         IBinder binder = listener.asBinder();
@@ -2137,6 +2239,7 @@
         return receiver;
     }
 
+    @GuardedBy("mLock")
     private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
             WorkSource workSource, boolean hideFromAppOps) {
         Receiver receiver = mReceivers.get(intent);
@@ -2202,67 +2305,65 @@
         throw new SecurityException("invalid package name: " + packageName);
     }
 
-    private void checkPendingIntent(PendingIntent intent) {
-        if (intent == null) {
-            throw new IllegalArgumentException("invalid pending intent: " + null);
-        }
-    }
-
-    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
-            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
-        if (intent == null && listener == null) {
-            throw new IllegalArgumentException("need either listener or intent");
-        } else if (intent != null && listener != null) {
-            throw new IllegalArgumentException("cannot register both listener and intent");
-        } else if (intent != null) {
-            checkPendingIntent(intent);
-            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
-        } else {
-            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
-        }
-    }
-
     @Override
     public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
             PendingIntent intent, String packageName) {
-        if (request == null) request = DEFAULT_LOCATION_REQUEST;
-        checkPackageName(packageName);
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
-                request.getProvider());
-        WorkSource workSource = request.getWorkSource();
-        if (workSource != null && !workSource.isEmpty()) {
-            checkDeviceStatsAllowed();
-        }
-        boolean hideFromAppOps = request.getHideFromAppOps();
-        if (hideFromAppOps) {
-            checkUpdateAppOpsAllowed();
-        }
-        boolean callerHasLocationHardwarePermission =
-                mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
-                        == PERMISSION_GRANTED;
-        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
-                callerHasLocationHardwarePermission);
-
-        final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
-        // providers may use public location API's, need to clear identity
-        long identity = Binder.clearCallingIdentity();
-        try {
-            // We don't check for MODE_IGNORED here; we will do that when we go to deliver
-            // a location.
-            checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
-
-            synchronized (mLock) {
-                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
-                        packageName, workSource, hideFromAppOps);
-                requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
+        synchronized (mLock) {
+            if (request == null) request = DEFAULT_LOCATION_REQUEST;
+            checkPackageName(packageName);
+            int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+            checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
+                    request.getProvider());
+            WorkSource workSource = request.getWorkSource();
+            if (workSource != null && !workSource.isEmpty()) {
+                mContext.enforceCallingOrSelfPermission(
+                        Manifest.permission.UPDATE_DEVICE_STATS, null);
             }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            boolean hideFromAppOps = request.getHideFromAppOps();
+            if (hideFromAppOps) {
+                mContext.enforceCallingOrSelfPermission(
+                        Manifest.permission.UPDATE_APP_OPS_STATS, null);
+            }
+            boolean callerHasLocationHardwarePermission =
+                    mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+                            == PERMISSION_GRANTED;
+            LocationRequest sanitizedRequest = createSanitizedRequest(request,
+                    allowedResolutionLevel,
+                    callerHasLocationHardwarePermission);
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+
+            long identity = Binder.clearCallingIdentity();
+            try {
+
+                // We don't check for MODE_IGNORED here; we will do that when we go to deliver
+                // a location.
+                checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+
+                if (intent == null && listener == null) {
+                    throw new IllegalArgumentException("need either listener or intent");
+                } else if (intent != null && listener != null) {
+                    throw new IllegalArgumentException(
+                            "cannot register both listener and intent");
+                }
+
+                Receiver receiver;
+                if (intent != null) {
+                    receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
+                            hideFromAppOps);
+                } else {
+                    receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
+                            hideFromAppOps);
+                }
+                requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
+    @GuardedBy("mLock")
     private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
             int uid, String packageName) {
         // Figure out the provider. Either its explicitly request (legacy use cases), or
@@ -2273,7 +2374,7 @@
             throw new IllegalArgumentException("provider name must not be null");
         }
 
-        LocationProvider provider = mProvidersByName.get(name);
+        LocationProvider provider = getLocationProviderLocked(name);
         if (provider == null) {
             throw new IllegalArgumentException("provider doesn't exist: " + name);
         }
@@ -2292,7 +2393,7 @@
             oldRecord.disposeLocked(false);
         }
 
-        if (provider.isEnabled()) {
+        if (provider.isUseableLocked()) {
             applyRequirementsLocked(name);
         } else {
             // Notify the listener that updates are currently disabled
@@ -2308,14 +2409,23 @@
             String packageName) {
         checkPackageName(packageName);
 
-        final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
+        int uid = Binder.getCallingUid();
+
+        if (intent == null && listener == null) {
+            throw new IllegalArgumentException("need either listener or intent");
+        } else if (intent != null && listener != null) {
+            throw new IllegalArgumentException("cannot register both listener and intent");
+        }
 
         synchronized (mLock) {
-            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
-                    packageName, null, false);
+            Receiver receiver;
+            if (intent != null) {
+                receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
+            } else {
+                receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
+            }
 
-            // providers may use public location API's, need to clear identity
             long identity = Binder.clearCallingIdentity();
             try {
                 removeUpdatesLocked(receiver);
@@ -2325,6 +2435,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void removeUpdatesLocked(Receiver receiver) {
         if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
 
@@ -2356,51 +2467,53 @@
         }
     }
 
-    private void applyAllProviderRequirementsLocked() {
-        for (LocationProvider p : mProviders) {
-            applyRequirementsLocked(p.getName());
-        }
-    }
-
     @Override
-    public Location getLastLocation(LocationRequest request, String packageName) {
-        if (D) Log.d(TAG, "getLastLocation: " + request);
-        if (request == null) request = DEFAULT_LOCATION_REQUEST;
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkPackageName(packageName);
-        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
-                request.getProvider());
-        // no need to sanitize this request, as only the provider name is used
+    public Location getLastLocation(LocationRequest r, String packageName) {
+        if (D) Log.d(TAG, "getLastLocation: " + r);
+        synchronized (mLock) {
+            LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
+            int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+            checkPackageName(packageName);
+            checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
+                    request.getProvider());
+            // no need to sanitize this request, as only the provider name is used
 
-        final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            if (mBlacklist.isBlacklisted(packageName)) {
-                if (D) {
-                    Log.d(TAG, "not returning last loc for blacklisted app: " +
-                            packageName);
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (mBlacklist.isBlacklisted(packageName)) {
+                    if (D) {
+                        Log.d(TAG, "not returning last loc for blacklisted app: "
+                                + packageName);
+                    }
+                    return null;
                 }
-                return null;
-            }
 
-            if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
-                if (D) {
-                    Log.d(TAG, "not returning last loc for no op app: " +
-                            packageName);
+                if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
+                    if (D) {
+                        Log.d(TAG, "not returning last loc for no op app: "
+                                + packageName);
+                    }
+                    return null;
                 }
-                return null;
-            }
 
-            synchronized (mLock) {
                 // Figure out the provider. Either its explicitly request (deprecated API's),
                 // or use the fused provider
                 String name = request.getProvider();
                 if (name == null) name = LocationManager.FUSED_PROVIDER;
-                LocationProvider provider = mProvidersByName.get(name);
+                LocationProvider provider = getLocationProviderLocked(name);
                 if (provider == null) return null;
 
-                if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
+                // only the current user or location providers may get location this way
+                if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
+                        uid)) {
+                    return null;
+                }
+
+                if (!provider.isUseableLocked()) {
+                    return null;
+                }
 
                 Location location;
                 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
@@ -2416,9 +2529,12 @@
 
                 // Don't return stale location to apps with foreground-only location permission.
                 String op = resolutionLevelToOpStr(allowedResolutionLevel);
-                long locationAgeMs = SystemClock.elapsedRealtime() -
-                        location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
-                if ((locationAgeMs > mLastLocationMaxAgeMs)
+                long locationAgeMs = SystemClock.elapsedRealtime()
+                        - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
+                if ((locationAgeMs > Settings.Global.getLong(
+                        mContext.getContentResolver(),
+                        Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
+                        DEFAULT_LAST_LOCATION_MAX_AGE_MS))
                         && (mAppOps.unsafeCheckOp(op, uid, packageName)
                         == AppOpsManager.MODE_FOREGROUND)) {
                     return null;
@@ -2433,24 +2549,13 @@
                 } else {
                     return new Location(location);
                 }
+                return null;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
-            return null;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
-    /**
-     * Provides an interface to inject and set the last location if location is not available
-     * currently.
-     *
-     * This helps in cases where the product (Cars for example) has saved the last known location
-     * before powering off.  This interface lets the client inject the saved location while the GPS
-     * chipset is getting its first fix, there by improving user experience.
-     *
-     * @param location - Location object to inject
-     * @return true if update was successful, false if not
-     */
     @Override
     public boolean injectLocation(Location location) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -2464,38 +2569,23 @@
             }
             return false;
         }
-        LocationProvider p = null;
-        String provider = location.getProvider();
-        if (provider != null) {
-            p = mProvidersByName.get(provider);
-        }
-        if (p == null) {
-            if (D) {
-                Log.d(TAG, "injectLocation(): unknown provider");
-            }
-            return false;
-        }
+
         synchronized (mLock) {
-            if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
-                if (D) {
-                    Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
-                }
+            LocationProvider provider = getLocationProviderLocked(location.getProvider());
+            if (provider == null || !provider.isUseableLocked()) {
                 return false;
-            } else {
-                // NOTE: If last location is already available, location is not injected.  If
-                // provider's normal source (like a GPS chipset) have already provided an output,
-                // there is no need to inject this location.
-                if (mLastLocation.get(provider) == null) {
-                    updateLastLocationLocked(location, provider);
-                } else {
-                    if (D) {
-                        Log.d(TAG, "injectLocation(): Location exists. Not updating");
-                    }
-                    return false;
-                }
             }
+
+            // NOTE: If last location is already available, location is not injected.  If
+            // provider's normal source (like a GPS chipset) have already provided an output
+            // there is no need to inject this location.
+            if (mLastLocation.get(provider.getName()) != null) {
+                return false;
+            }
+
+            updateLastLocationLocked(location, provider.getName());
+            return true;
         }
-        return true;
     }
 
     @Override
@@ -2504,39 +2594,49 @@
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
-        checkPendingIntent(intent);
-        checkPackageName(packageName);
-        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
-                request.getProvider());
-        // Require that caller can manage given document
-        boolean callerHasLocationHardwarePermission =
-                mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
-                        == PERMISSION_GRANTED;
-        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
-                callerHasLocationHardwarePermission);
-
-        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
-
-        // geo-fence manager uses the public location API, need to clear identity
-        int uid = Binder.getCallingUid();
-        // TODO: http://b/23822629
-        if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
-            // temporary measure until geofences work for secondary users
-            Log.w(TAG, "proximity alerts are currently available only to the primary user");
-            return;
+        if (intent == null) {
+            throw new IllegalArgumentException("invalid pending intent: " + null);
         }
-        long identity = Binder.clearCallingIdentity();
-        try {
-            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
-                    uid, packageName);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+        checkPackageName(packageName);
+        synchronized (mLock) {
+            checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
+                    request.getProvider());
+            // Require that caller can manage given document
+            boolean callerHasLocationHardwarePermission =
+                    mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+                            == PERMISSION_GRANTED;
+            LocationRequest sanitizedRequest = createSanitizedRequest(request,
+                    allowedResolutionLevel,
+                    callerHasLocationHardwarePermission);
+
+            if (D) {
+                Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
+            }
+
+            // geo-fence manager uses the public location API, need to clear identity
+            int uid = Binder.getCallingUid();
+            // TODO: http://b/23822629
+            if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
+                // temporary measure until geofences work for secondary users
+                Log.w(TAG, "proximity alerts are currently available only to the primary user");
+                return;
+            }
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
+                        allowedResolutionLevel,
+                        uid, packageName);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
     @Override
     public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
-        checkPendingIntent(intent);
+        if (intent == null) {
+            throw new IllegalArgumentException("invalid pending intent: " + null);
+        }
         checkPackageName(packageName);
 
         if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
@@ -2641,6 +2741,7 @@
         synchronized (mLock) {
             Identity callerIdentity
                     = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+
             // TODO(b/120481270): Register for client death notification and update map.
             mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
             long identity = Binder.clearCallingIdentity();
@@ -2670,25 +2771,26 @@
     }
 
     @Override
-    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
-        if (provider == null) {
+    public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
+        if (providerName == null) {
             // throw NullPointerException to remain compatible with previous implementation
             throw new NullPointerException();
         }
-        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
-                provider);
-
-        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
-        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
-                != PERMISSION_GRANTED)) {
-            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
-        }
-
         synchronized (mLock) {
-            LocationProvider p = mProvidersByName.get(provider);
-            if (p == null) return false;
+            checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
+                    providerName);
 
-            p.sendExtraCommand(command, extras);
+            // and check for ACCESS_LOCATION_EXTRA_COMMANDS
+            if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
+                    != PERMISSION_GRANTED)) {
+                throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
+            }
+
+            LocationProvider provider = getLocationProviderLocked(providerName);
+            if (provider != null) {
+                provider.sendExtraCommandLocked(command, extras);
+            }
+
             return true;
         }
     }
@@ -2707,44 +2809,29 @@
         }
     }
 
-    /**
-     * @return null if the provider does not exist
-     * @throws SecurityException if the provider is not allowed to be
-     *                           accessed by the caller
-     */
     @Override
-    public ProviderProperties getProviderProperties(String provider) {
-        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
-                provider);
-
-        LocationProvider p;
+    public ProviderProperties getProviderProperties(String providerName) {
         synchronized (mLock) {
-            p = mProvidersByName.get(provider);
-        }
+            checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
+                    providerName);
 
-        if (p == null) return null;
-        return p.getProperties();
+            LocationProvider provider = getLocationProviderLocked(providerName);
+            if (provider == null) {
+                return null;
+            }
+            return provider.getPropertiesLocked();
+        }
     }
 
-    /**
-     * @return null if the provider does not exist
-     * @throws SecurityException if the provider is not allowed to be
-     *                           accessed by the caller
-     */
     @Override
     public String getNetworkProviderPackage() {
-        LocationProvider p;
         synchronized (mLock) {
-            p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
+            LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
+            if (provider == null) {
+                return null;
+            }
+            return provider.getPackageLocked();
         }
-
-        if (p == null) {
-            return null;
-        }
-        if (p.mProvider instanceof LocationProviderProxy) {
-            return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
-        }
-        return null;
     }
 
     @Override
@@ -2780,241 +2867,96 @@
         }
     }
 
-    /**
-     * Returns the current location enabled/disabled status for a user
-     *
-     * @param userId the id of the user
-     * @return true if location is enabled
-     */
+    private boolean isLocationEnabled() {
+        return isLocationEnabledForUser(mCurrentUserId);
+    }
+
     @Override
     public boolean isLocationEnabledForUser(int userId) {
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
-        checkInteractAcrossUsersPermission(userId);
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    "Requires INTERACT_ACROSS_USERS permission");
+        }
 
         long identity = Binder.clearCallingIdentity();
         try {
-            synchronized (mLock) {
-                final String allowedProviders = Settings.Secure.getStringForUser(
+            boolean enabled;
+            try {
+                enabled = Settings.Secure.getIntForUser(
+                        mContext.getContentResolver(),
+                        Settings.Secure.LOCATION_MODE,
+                        userId) != Settings.Secure.LOCATION_MODE_OFF;
+            } catch (Settings.SettingNotFoundException e) {
+                // OS upgrade case where mode isn't set yet
+                enabled = !TextUtils.isEmpty(Settings.Secure.getStringForUser(
                         mContext.getContentResolver(),
                         Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        userId);
-                if (allowedProviders == null) {
-                    return false;
+                        userId));
+
+                try {
+                    Settings.Secure.putIntForUser(
+                            mContext.getContentResolver(),
+                            Settings.Secure.LOCATION_MODE,
+                            enabled
+                                    ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+                                    : Settings.Secure.LOCATION_MODE_OFF,
+                            userId);
+                } catch (RuntimeException ex) {
+                    // any problem with writing should not be propagated
+                    Slog.e(TAG, "error updating location mode", ex);
                 }
-                final List<String> providerList = Arrays.asList(allowedProviders.split(","));
-                for (String provider : mRealProviders.keySet()) {
-                    if (provider.equals(LocationManager.PASSIVE_PROVIDER)
-                            || provider.equals(LocationManager.FUSED_PROVIDER)) {
-                        continue;
-                    }
-                    if (providerList.contains(provider)) {
-                        return true;
-                    }
-                }
-                return false;
             }
+            return enabled;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
-    /**
-     * Enable or disable location for a user
-     *
-     * @param enabled true to enable location, false to disable location
-     * @param userId  the id of the user
-     */
-    @Override
-    public void setLocationEnabledForUser(boolean enabled, int userId) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.WRITE_SECURE_SETTINGS,
-                "Requires WRITE_SECURE_SETTINGS permission");
-
-        // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
-        checkInteractAcrossUsersPermission(userId);
-
-        long identity = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                final Set<String> allRealProviders = mRealProviders.keySet();
-                // Update all providers on device plus gps and network provider when disabling
-                // location
-                Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
-                allProvidersSet.addAll(allRealProviders);
-                // When disabling location, disable gps and network provider that could have been
-                // enabled by location mode api.
-                if (!enabled) {
-                    allProvidersSet.add(LocationManager.GPS_PROVIDER);
-                    allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
-                }
-                if (allProvidersSet.isEmpty()) {
-                    return;
-                }
-                // to ensure thread safety, we write the provider name with a '+' or '-'
-                // and let the SettingsProvider handle it rather than reading and modifying
-                // the list of enabled providers.
-                final String prefix = enabled ? "+" : "-";
-                StringBuilder locationProvidersAllowed = new StringBuilder();
-                for (String provider : allProvidersSet) {
-                    if (provider.equals(LocationManager.PASSIVE_PROVIDER)
-                            || provider.equals(LocationManager.FUSED_PROVIDER)) {
-                        continue;
-                    }
-                    locationProvidersAllowed.append(prefix);
-                    locationProvidersAllowed.append(provider);
-                    locationProvidersAllowed.append(",");
-                }
-                // Remove the trailing comma
-                locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
-                Settings.Secure.putStringForUser(
-                        mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        locationProvidersAllowed.toString(),
-                        userId);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    /**
-     * Returns the current enabled/disabled status of a location provider and user
-     *
-     * @param providerName name of the provider
-     * @param userId       the id of the user
-     * @return true if the provider exists and is enabled
-     */
     @Override
     public boolean isProviderEnabledForUser(String providerName, int userId) {
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
-        checkInteractAcrossUsersPermission(userId);
-
-        if (!isLocationEnabledForUser(userId)) {
-            return false;
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    "Requires INTERACT_ACROSS_USERS permission");
         }
 
         // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
         // so we discourage its use
-        if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
+        if (FUSED_PROVIDER.equals(providerName)) return false;
 
-        long identity = Binder.clearCallingIdentity();
-        try {
-            LocationProvider provider;
-            synchronized (mLock) {
-                provider = mProvidersByName.get(providerName);
-            }
-            return provider != null && provider.isEnabled();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+        synchronized (mLock) {
+            LocationProvider provider = getLocationProviderLocked(providerName);
+            return provider != null && provider.isUseableForUserLocked(userId);
         }
     }
 
-    /**
-     * Enable or disable a single location provider.
-     *
-     * @param provider name of the provider
-     * @param enabled  true to enable the provider. False to disable the provider
-     * @param userId   the id of the user to set
-     * @return true if the value was set, false on errors
-     */
-    @Override
-    public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
-        return false;
-    }
-
-    /**
-     * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
-     * current user id
-     *
-     * @param userId the user id to get or set value
-     */
-    private void checkInteractAcrossUsersPermission(int userId) {
-        int uid = Binder.getCallingUid();
-        if (UserHandle.getUserId(uid) != userId) {
-            if (ActivityManager.checkComponentPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
-                    != PERMISSION_GRANTED) {
-                throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
-            }
-        }
-    }
-
-    /**
-     * Returns "true" if the UID belongs to a bound location provider.
-     *
-     * @param uid the uid
-     * @return true if uid belongs to a bound location provider
-     */
-    private boolean isUidALocationProvider(int uid) {
+    @GuardedBy("mLock")
+    private boolean isLocationProviderLocked(int uid) {
         if (uid == Process.SYSTEM_UID) {
             return true;
         }
-        if (mGeocodeProvider != null) {
-            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
-        }
-        for (LocationProviderProxy proxy : mProxyProviders) {
-            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
-        }
-        return false;
-    }
 
-    private void checkCallerIsProvider() {
-        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
-                == PERMISSION_GRANTED) {
-            return;
-        }
-
-        // Previously we only used the INSTALL_LOCATION_PROVIDER
-        // check. But that is system or signature
-        // protection level which is not flexible enough for
-        // providers installed oustide the system image. So
-        // also allow providers with a UID matching the
-        // currently bound package name
-
-        if (isUidALocationProvider(Binder.getCallingUid())) {
-            return;
-        }
-
-        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
-                "or UID of a currently bound location provider");
-    }
-
-    /**
-     * Returns true if the given package belongs to the given uid.
-     */
-    private boolean doesUidHavePackage(int uid, String packageName) {
-        if (packageName == null) {
-            return false;
-        }
         String[] packageNames = mPackageManager.getPackagesForUid(uid);
         if (packageNames == null) {
             return false;
         }
-        for (String name : packageNames) {
-            if (packageName.equals(name)) {
+        for (LocationProvider provider : mProviders) {
+            String packageName = provider.getPackageLocked();
+            if (packageName == null) {
+                continue;
+            }
+            if (ArrayUtils.contains(packageNames, packageName)) {
                 return true;
             }
         }
         return false;
     }
 
-    @Override
-    public void reportLocation(Location location, boolean passive) {
-        checkCallerIsProvider();
-
-        if (!location.isComplete()) {
-            Log.w(TAG, "Dropping incomplete location: " + location);
-            return;
-        }
-
-        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
-        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
-        m.arg1 = (passive ? 1 : 0);
-        mLocationHandler.sendMessageAtFrontOfQueue(m);
-    }
-
-
-    private static boolean shouldBroadcastSafe(
+    @GuardedBy("mLock")
+    private static boolean shouldBroadcastSafeLocked(
             Location loc, Location lastLoc, UpdateRecord record, long now) {
         // Always broadcast the first update
         if (lastLoc == null) {
@@ -3046,26 +2988,36 @@
         return record.mRealRequest.getExpireAt() >= now;
     }
 
-    private void handleLocationChangedLocked(Location location, boolean passive) {
+    @GuardedBy("mLock")
+    private void handleLocationChangedLocked(Location location, LocationProvider provider) {
+        if (!mProviders.contains(provider)) {
+            return;
+        }
+        if (!location.isComplete()) {
+            Log.w(TAG, "Dropping incomplete location: " + location);
+            return;
+        }
+
+        if (!provider.isPassiveLocked()) {
+            // notify passive provider of the new location
+            mPassiveProvider.updateLocation(location);
+        }
+
         if (D) Log.d(TAG, "incoming location: " + location);
         long now = SystemClock.elapsedRealtime();
-        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
-        // Skip if the provider is unknown.
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) return;
-        updateLastLocationLocked(location, provider);
+        updateLastLocationLocked(location, provider.getName());
         // mLastLocation should have been updated from the updateLastLocationLocked call above.
-        Location lastLocation = mLastLocation.get(provider);
+        Location lastLocation = mLastLocation.get(provider.getName());
         if (lastLocation == null) {
             Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
             return;
         }
 
         // Update last known coarse interval location if enough time has passed.
-        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
+        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider.getName());
         if (lastLocationCoarseInterval == null) {
             lastLocationCoarseInterval = new Location(location);
-            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
+            mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
         }
         long timeDiffNanos = location.getElapsedRealtimeNanos()
                 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
@@ -3079,7 +3031,7 @@
                 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
 
         // Skip if there are no UpdateRecords for this provider.
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
         if (records == null || records.size() == 0) return;
 
         // Fetch coarse location
@@ -3088,13 +3040,6 @@
             coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
         }
 
-        // Fetch latest status update time
-        long newStatusUpdateTime = p.getStatusUpdateTime();
-
-        // Get latest status
-        Bundle extras = new Bundle();
-        int status = p.getStatus(extras);
-
         ArrayList<Receiver> deadReceivers = null;
         ArrayList<UpdateRecord> deadUpdateRecords = null;
 
@@ -3104,8 +3049,8 @@
             boolean receiverDead = false;
 
             int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
-            if (!isCurrentProfile(receiverUserId)
-                    && !isUidALocationProvider(receiver.mIdentity.mUid)) {
+            if (!isCurrentProfileLocked(receiverUserId)
+                    && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
                 if (D) {
                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
                             " (current user: " + mCurrentUserId + ", app: " +
@@ -3142,7 +3087,8 @@
             }
             if (notifyLocation != null) {
                 Location lastLoc = r.mLastFixBroadcast;
-                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
+                if ((lastLoc == null)
+                        || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
                     if (lastLoc == null) {
                         lastLoc = new Location(notifyLocation);
                         r.mLastFixBroadcast = lastLoc;
@@ -3150,7 +3096,8 @@
                         lastLoc.set(notifyLocation);
                     }
                     if (!receiver.callLocationChangedLocked(notifyLocation)) {
-                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
+                        Slog.w(TAG, "RemoteException calling onLocationChanged on "
+                                + receiver);
                         receiverDead = true;
                     }
                     r.mRealRequest.decrementNumUpdates();
@@ -3161,12 +3108,16 @@
             // guarded behind this setting now. should be removed completely post-Q
             if (Settings.Global.getInt(mContext.getContentResolver(),
                     LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
+                long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
+                Bundle extras = new Bundle();
+                int status = provider.getStatusLocked(extras);
+
                 long prevStatusUpdateTime = r.mLastStatusBroadcast;
                 if ((newStatusUpdateTime > prevStatusUpdateTime)
                         && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
 
                     r.mLastStatusBroadcast = newStatusUpdateTime;
-                    if (!receiver.callStatusChangedLocked(provider, status, extras)) {
+                    if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
                         receiverDead = true;
                         Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
                     }
@@ -3205,12 +3156,7 @@
         }
     }
 
-    /**
-     * Updates last location with the given location
-     *
-     * @param location new location to update
-     * @param provider Location provider to update for
-     */
+    @GuardedBy("mLock")
     private void updateLastLocationLocked(Location location, String provider) {
         Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
         Location lastNoGPSLocation;
@@ -3229,75 +3175,6 @@
         lastLocation.set(location);
     }
 
-    private class LocationWorkerHandler extends Handler {
-        public LocationWorkerHandler(Looper looper) {
-            super(looper, null, true);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_LOCATION_CHANGED:
-                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
-                    break;
-            }
-        }
-    }
-
-    private boolean isMockProvider(String provider) {
-        synchronized (mLock) {
-            return mMockProviders.containsKey(provider);
-        }
-    }
-
-    private void handleLocationChanged(Location location, boolean passive) {
-        // create a working copy of the incoming Location so that the service can modify it without
-        // disturbing the caller's copy
-        Location myLocation = new Location(location);
-        String provider = myLocation.getProvider();
-
-        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
-        // bit if location did not come from a mock provider because passive/fused providers can
-        // forward locations from mock providers, and should not grant them legitimacy in doing so.
-        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
-            myLocation.setIsFromMockProvider(true);
-        }
-
-        synchronized (mLock) {
-            if (!passive) {
-                // notify passive provider of the new location
-                mPassiveProvider.updateLocation(myLocation);
-            }
-            handleLocationChangedLocked(myLocation, passive);
-        }
-    }
-
-    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
-        @Override
-        public void onPackageDisappeared(String packageName, int reason) {
-            // remove all receivers associated with this package name
-            synchronized (mLock) {
-                ArrayList<Receiver> deadReceivers = null;
-
-                for (Receiver receiver : mReceivers.values()) {
-                    if (receiver.mIdentity.mPackageName.equals(packageName)) {
-                        if (deadReceivers == null) {
-                            deadReceivers = new ArrayList<>();
-                        }
-                        deadReceivers.add(receiver);
-                    }
-                }
-
-                // perform removal outside of mReceivers loop
-                if (deadReceivers != null) {
-                    for (Receiver receiver : deadReceivers) {
-                        removeUpdatesLocked(receiver);
-                    }
-                }
-            }
-        }
-    };
-
     // Geocoder
 
     @Override
@@ -3343,63 +3220,60 @@
             return;
         }
 
-        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
+        if (PASSIVE_PROVIDER.equals(name)) {
             throw new IllegalArgumentException("Cannot mock the passive location provider");
         }
 
-        long identity = Binder.clearCallingIdentity();
         synchronized (mLock) {
-            // remove the real provider if we are replacing GPS or network provider
-            if (LocationManager.GPS_PROVIDER.equals(name)
-                    || LocationManager.NETWORK_PROVIDER.equals(name)
-                    || LocationManager.FUSED_PROVIDER.equals(name)) {
-                LocationProvider p = mProvidersByName.get(name);
-                if (p != null) {
-                    removeProviderLocked(p);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                LocationProvider oldProvider = getLocationProviderLocked(name);
+                if (oldProvider != null) {
+                    if (oldProvider.isMock()) {
+                        throw new IllegalArgumentException(
+                                "Provider \"" + name + "\" already exists");
+                    }
+
+                    removeProviderLocked(oldProvider);
                 }
+
+                MockLocationProvider mockProviderManager = new MockLocationProvider(name);
+                addProviderLocked(mockProviderManager);
+                mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
-            addTestProviderLocked(name, properties);
         }
-        Binder.restoreCallingIdentity(identity);
-    }
-
-    private void addTestProviderLocked(String name, ProviderProperties properties) {
-        if (mProvidersByName.get(name) != null) {
-            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
-        }
-
-        LocationProvider provider = new LocationProvider(name);
-        MockProvider mockProvider = new MockProvider(provider, properties);
-
-        addProviderLocked(provider);
-        mMockProviders.put(name, mockProvider);
-        mLastLocation.put(name, null);
-        mLastLocationCoarseInterval.put(name, null);
     }
 
     @Override
-    public void removeTestProvider(String provider, String opPackageName) {
+    public void removeTestProvider(String name, String opPackageName) {
         if (!canCallerAccessMockLocation(opPackageName)) {
             return;
         }
 
         synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.remove(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
-            }
-
             long identity = Binder.clearCallingIdentity();
             try {
-                removeProviderLocked(mProvidersByName.get(provider));
+                LocationProvider testProvider = getLocationProviderLocked(name);
+                if (testProvider == null || !testProvider.isMock()) {
+                    throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
+                }
+
+                removeProviderLocked(testProvider);
 
                 // reinstate real provider if available
-                LocationProvider realProvider = mRealProviders.get(provider);
+                LocationProvider realProvider = null;
+                for (LocationProvider provider : mRealProviders) {
+                    if (name.equals(provider.getName())) {
+                        realProvider = provider;
+                        break;
+                    }
+                }
+
                 if (realProvider != null) {
                     addProviderLocked(realProvider);
                 }
-                mLastLocation.put(provider, null);
-                mLastLocationCoarseInterval.put(provider, null);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -3407,78 +3281,60 @@
     }
 
     @Override
-    public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
-        if (!canCallerAccessMockLocation(opPackageName)) {
-            return;
-        }
-
-        synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.get(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
-            }
-
-            // Ensure that the location is marked as being mock. There's some logic to do this in
-            // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
-            Location mock = new Location(loc);
-            mock.setIsFromMockProvider(true);
-
-            if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
-                // The location has an explicit provider that is different from the mock provider
-                // name. The caller may be trying to fool us via bug 33091107.
-                EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
-                        provider + "!=" + loc.getProvider());
-            }
-
-            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mockProvider.setLocation(mock);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
-        if (!canCallerAccessMockLocation(opPackageName)) {
-            return;
-        }
-
-        synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.get(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
-            }
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mockProvider.setEnabled(enabled);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
+    public void setTestProviderLocation(String providerName, Location location,
             String opPackageName) {
         if (!canCallerAccessMockLocation(opPackageName)) {
             return;
         }
 
         synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.get(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            if (testProvider == null || !testProvider.isMock()) {
+                throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
             }
-            mockProvider.setStatus(status, extras, updateTime);
+
+            String locationProvider = location.getProvider();
+            if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
+                // The location has an explicit provider that is different from the mock
+                // provider name. The caller may be trying to fool us via b/33091107.
+                EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+                        providerName + "!=" + location.getProvider());
+            }
+
+            ((MockLocationProvider) testProvider).setLocationLocked(location);
         }
     }
 
-    private void log(String log) {
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Slog.d(TAG, log);
+    @Override
+    public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
+        if (!canCallerAccessMockLocation(opPackageName)) {
+            return;
+        }
+
+        synchronized (mLock) {
+            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            if (testProvider == null || !testProvider.isMock()) {
+                throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
+            }
+
+            ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
+        }
+    }
+
+    @Override
+    public void setTestProviderStatus(String providerName, int status, Bundle extras,
+            long updateTime, String opPackageName) {
+        if (!canCallerAccessMockLocation(opPackageName)) {
+            return;
+        }
+
+        synchronized (mLock) {
+            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            if (testProvider == null || !testProvider.isMock()) {
+                throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
+            }
+
+            ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
         }
     }
 
@@ -3494,6 +3350,7 @@
                 return;
             }
             pw.println("Current Location Manager state:");
+            pw.println("  Location Mode: " + isLocationEnabled());
             pw.println("  Location Listeners:");
             for (Receiver receiver : mReceivers.values()) {
                 pw.println("    " + receiver);
@@ -3548,12 +3405,6 @@
 
             pw.append("  ");
             mBlacklist.dump(pw);
-            if (mMockProviders.size() > 0) {
-                pw.println("  Mock Providers:");
-                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
-                    i.getValue().dump(fd, pw, args);
-                }
-            }
 
             if (mLocationControllerExtraPackage != null) {
                 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
@@ -3574,7 +3425,7 @@
                 return;
             }
             for (LocationProvider provider : mProviders) {
-                provider.dump(fd, pw, args);
+                provider.dumpLocked(fd, pw, args);
             }
             if (mGnssBatchingInProgress) {
                 pw.println("  GNSS batching in progress");
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index f27d373..8adc416 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Environment;
 import android.os.Handler;
@@ -29,6 +30,7 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
@@ -46,8 +48,10 @@
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Monitors the health of packages on the system and notifies interested observers when packages
@@ -58,7 +62,7 @@
     // Duration to count package failures before it resets to 0
     private static final int TRIGGER_DURATION_MS = 60000;
     // Number of package failures within the duration above before we notify observers
-    private static final int TRIGGER_FAILURE_COUNT = 5;
+    static final int TRIGGER_FAILURE_COUNT = 5;
     private static final int DB_VERSION = 1;
     private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
     private static final String TAG_PACKAGE = "package";
@@ -75,20 +79,13 @@
     // Handler to run package cleanup runnables
     private final Handler mTimerHandler;
     private final Handler mIoHandler;
-    // Contains (observer-name -> external-observer-handle) that have been registered during the
-    // current boot.
-    // It is populated when observers call #registerHealthObserver and it does not survive reboots.
-    @GuardedBy("mLock")
-    final ArrayMap<String, PackageHealthObserver> mRegisteredObservers = new ArrayMap<>();
-    // Contains (observer-name -> internal-observer-handle) that have ever been registered from
+    // Contains (observer-name -> observer-handle) that have ever been registered from
     // previous boots. Observers with all packages expired are periodically pruned.
     // It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
     @GuardedBy("mLock")
-    final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
+    private final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
     // File containing the XML data of monitored packages /data/system/package-watchdog.xml
-    private final AtomicFile mPolicyFile =
-            new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
-                           "package-watchdog.xml"));
+    private final AtomicFile mPolicyFile;
     // Runnable to prune monitored packages that have expired
     private final Runnable mPackageCleanup;
     // Last SystemClock#uptimeMillis a package clean up was executed.
@@ -98,14 +95,32 @@
     // 0 if mPackageCleanup not running.
     private long mDurationAtLastReschedule;
 
+    // TODO(zezeozue): Remove redundant context param
     private PackageWatchdog(Context context) {
         mContext = context;
+        mPolicyFile = new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
+                        "package-watchdog.xml"));
         mTimerHandler = new Handler(Looper.myLooper());
         mIoHandler = BackgroundThread.getHandler();
         mPackageCleanup = this::rescheduleCleanup;
         loadFromFile();
     }
 
+    /**
+     * Creates a PackageWatchdog for testing that uses the same {@code looper} for all handlers
+     * and creates package-watchdog.xml in an apps data directory.
+     */
+    @VisibleForTesting
+    PackageWatchdog(Context context, Looper looper) {
+        mContext = context;
+        mPolicyFile = new AtomicFile(new File(context.getFilesDir(), "package-watchdog.xml"));
+        mTimerHandler = new Handler(looper);
+        mIoHandler = mTimerHandler;
+        mPackageCleanup = this::rescheduleCleanup;
+        loadFromFile();
+    }
+
+
     /** Creates or gets singleton instance of PackageWatchdog. */
     public static PackageWatchdog getInstance(Context context) {
         synchronized (PackageWatchdog.class) {
@@ -124,7 +139,10 @@
      */
     public void registerHealthObserver(PackageHealthObserver observer) {
         synchronized (mLock) {
-            mRegisteredObservers.put(observer.getName(), observer);
+            ObserverInternal internalObserver = mAllObservers.get(observer.getName());
+            if (internalObserver != null) {
+                internalObserver.mRegisteredObserver = observer;
+            }
             if (mDurationAtLastReschedule == 0) {
                 // Nothing running, schedule
                 rescheduleCleanup();
@@ -143,7 +161,7 @@
      * or {@code durationMs} is less than 1
      */
     public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
-            int durationMs) {
+            long durationMs) {
         if (packageNames.isEmpty() || durationMs < 1) {
             throw new IllegalArgumentException("Observation not started, no packages specified"
                     + "or invalid duration");
@@ -180,11 +198,32 @@
     public void unregisterHealthObserver(PackageHealthObserver observer) {
         synchronized (mLock) {
             mAllObservers.remove(observer.getName());
-            mRegisteredObservers.remove(observer.getName());
         }
         saveToFileAsync();
     }
 
+    /**
+     * Returns packages observed by {@code observer}
+     *
+     * @return an empty set if {@code observer} has some packages observerd from a previous boot
+     * but has not registered itself in the current boot to receive notifications. Returns null
+     * if there are no active packages monitored from any boot.
+     */
+    @Nullable
+    public Set<String> getPackages(PackageHealthObserver observer) {
+        synchronized (mLock) {
+            for (int i = 0; i < mAllObservers.size(); i++) {
+                if (observer.getName().equals(mAllObservers.keyAt(i))) {
+                    if (observer.equals(mAllObservers.valueAt(i).mRegisteredObserver)) {
+                        return mAllObservers.valueAt(i).mPackages.keySet();
+                    }
+                    return Collections.emptySet();
+                }
+            }
+        }
+        return null;
+    }
+
     // TODO(zezeozue:) Accept current versionCodes of failing packages?
     /**
      * Called when a process fails either due to a crash or ANR.
@@ -198,24 +237,23 @@
     public void onPackageFailure(String[] packages) {
         ArrayMap<String, List<PackageHealthObserver>> packagesToReport = new ArrayMap<>();
         synchronized (mLock) {
-            if (mRegisteredObservers.isEmpty()) {
+            if (mAllObservers.isEmpty()) {
                 return;
             }
 
             for (int pIndex = 0; pIndex < packages.length; pIndex++) {
+                // Observers interested in receiving packageName failures
+                List<PackageHealthObserver> observersToNotify = new ArrayList<>();
                 for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
-                    // Observers interested in receiving packageName failures
-                    List<PackageHealthObserver> observersToNotify = new ArrayList<>();
-                    PackageHealthObserver activeObserver =
-                            mRegisteredObservers.get(mAllObservers.valueAt(oIndex).mName);
-                    if (activeObserver != null) {
-                        observersToNotify.add(activeObserver);
+                    PackageHealthObserver registeredObserver =
+                            mAllObservers.valueAt(oIndex).mRegisteredObserver;
+                    if (registeredObserver != null) {
+                        observersToNotify.add(registeredObserver);
                     }
-
-                    // Save interested observers and notify them outside the lock
-                    if (!observersToNotify.isEmpty()) {
-                        packagesToReport.put(packages[pIndex], observersToNotify);
-                    }
+                }
+                // Save interested observers and notify them outside the lock
+                if (!observersToNotify.isEmpty()) {
+                    packagesToReport.put(packages[pIndex], observersToNotify);
                 }
             }
         }
@@ -223,8 +261,11 @@
         // Notify observers
         for (int pIndex = 0; pIndex < packagesToReport.size(); pIndex++) {
             List<PackageHealthObserver> observers = packagesToReport.valueAt(pIndex);
+            String packageName = packages[pIndex];
             for (int oIndex = 0; oIndex < observers.size(); oIndex++) {
-                if (observers.get(oIndex).onHealthCheckFailed(packages[pIndex])) {
+                PackageHealthObserver observer = observers.get(oIndex);
+                if (mAllObservers.get(observer.getName()).onPackageFailure(packageName)
+                        && observer.onHealthCheckFailed(packageName)) {
                     // Observer has handled, do not notify others
                     break;
                 }
@@ -275,10 +316,12 @@
             // O if mPackageCleanup not running
             long elapsedDurationMs = mUptimeAtLastRescheduleMs == 0
                     ? 0 : uptimeMs - mUptimeAtLastRescheduleMs;
-            // O if mPackageCleanup not running
+            // Less than O if mPackageCleanup unexpectedly didn't run yet even though
+            // and we are past the last duration scheduled to run
             long remainingDurationMs = mDurationAtLastReschedule - elapsedDurationMs;
-
-            if (mUptimeAtLastRescheduleMs == 0 || nextDurationToScheduleMs < remainingDurationMs) {
+            if (mUptimeAtLastRescheduleMs == 0
+                    || remainingDurationMs <= 0
+                    || nextDurationToScheduleMs < remainingDurationMs) {
                 // First schedule or an earlier reschedule
                 pruneObservers(elapsedDurationMs);
                 mTimerHandler.removeCallbacks(mPackageCleanup);
@@ -305,6 +348,7 @@
             }
         }
         Slog.v(TAG, "Earliest package time is " + shortestDurationMs);
+
         return shortestDurationMs;
     }
 
@@ -409,6 +453,8 @@
     static class ObserverInternal {
         public final String mName;
         public final ArrayMap<String, MonitoredPackage> mPackages;
+        @Nullable
+        public PackageHealthObserver mRegisteredObserver;
 
         ObserverInternal(String name, List<MonitoredPackage> packages) {
             mName = name;
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index a9f190c..62da3f8 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -34,9 +34,9 @@
 import android.util.MathUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.StatsLog;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.PackageManagerService;
 
 import java.io.File;
 
@@ -179,6 +179,7 @@
     }
 
     private static void executeRescueLevelInternal(Context context, int level) throws Exception {
+        StatsLog.write(StatsLog.RESCUE_PARTY_RESET_REPORTED, level);
         switch (level) {
             case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
                 resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
new file mode 100644
index 0000000..93e1dd3
--- /dev/null
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+    "presubmit": [
+        {
+            "name": "FrameworksMockingServicesTests",
+            "options": [
+                {
+                  "include-annotation": "android.platform.test.annotations.Presubmit"
+                },
+                {
+                  "exclude-annotation": "android.support.test.filters.FlakyTest"
+                }
+            ]
+        }
+    ]
+}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 5d4c5c3..ea6d435 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -141,6 +141,7 @@
     private boolean mLowPowerMode;
     private int mHapticFeedbackIntensity;
     private int mNotificationIntensity;
+    private int mRingIntensity;
 
     native static boolean vibratorExists();
     native static void vibratorInit();
@@ -428,6 +429,10 @@
                     Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
                     true, mSettingObserver, UserHandle.USER_ALL);
 
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
+                    true, mSettingObserver, UserHandle.USER_ALL);
+
             mContext.registerReceiver(new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
@@ -534,12 +539,6 @@
                 return;
             }
             verifyIncomingUid(uid);
-            if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
-                    > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-                Slog.e(TAG, "Ignoring incoming vibration as process with uid = "
-                        + uid + " is background");
-                return;
-            }
             if (!verifyVibrationEffect(effect)) {
                 return;
             }
@@ -577,6 +576,13 @@
                 }
 
                 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
+                if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
+                        > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+                        && vib.isHapticFeedback()) {
+                    Slog.e(TAG, "Ignoring incoming vibration as process with uid = "
+                            + uid + " is background");
+                    return;
+                }
                 linkVibration(vib);
                 long ident = Binder.clearCallingIdentity();
                 try {
@@ -747,7 +753,9 @@
     }
 
     private int getCurrentIntensityLocked(Vibration vib) {
-        if (vib.isNotification() || vib.isRingtone()){
+        if (vib.isRingtone()) {
+            return mRingIntensity;
+        } else if (vib.isNotification()) {
             return mNotificationIntensity;
         } else if (vib.isHapticFeedback()) {
             return mHapticFeedbackIntensity;
@@ -769,7 +777,9 @@
         }
 
         final int defaultIntensity;
-        if (vib.isNotification() || vib.isRingtone()) {
+        if (vib.isRingtone()) {
+            defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
+        } else if (vib.isNotification()) {
             defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
         } else if (vib.isHapticFeedback()) {
             defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
@@ -932,6 +942,9 @@
         mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
                 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
+        mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.RING_VIBRATION_INTENSITY,
+                mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
     }
 
     @Override
@@ -1280,6 +1293,7 @@
             pw.println("  mLowPowerMode=" + mLowPowerMode);
             pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
             pw.println("  mNotificationIntensity=" + mNotificationIntensity);
+            pw.println("  mRingIntensity=" + mRingIntensity);
             pw.println("");
             pw.println("  Previous vibrations:");
             for (VibrationInfo info : mPreviousVibrations) {
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index e5ab8fc..c316915 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -31,6 +31,7 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.service.adb.AdbServiceDumpProto;
+import android.sysprop.AdbProperties;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -185,7 +186,7 @@
         mContext = context;
         mContentResolver = context.getContentResolver();
 
-        boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
+        boolean secureAdbEnabled = AdbProperties.secure().orElse(false);
         boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
         if (secureAdbEnabled && !dataEncrypted) {
             mDebuggingManager = new AdbDebuggingManager(context);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index ed39d83..0ff2a09 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -130,6 +130,9 @@
     // calling startForeground() before we ANR + stop it.
     static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
 
+    // For how long after a whitelisted service's start its process can start a background activity
+    private static final int SERVICE_BG_ACTIVITY_START_TIMEOUT_MS = 10*1000;
+
     final ActivityManagerService mAm;
 
     // Maximum number of services that we allow to start in the background
@@ -398,6 +401,14 @@
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
             int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
             throws TransactionTooLargeException {
+        return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
+                callingPackage, userId, false);
+    }
+
+    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
+            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
+            final int userId, boolean allowBackgroundActivityStarts)
+            throws TransactionTooLargeException {
         if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
                 + " type=" + resolvedType + " args=" + service.getExtras());
 
@@ -622,10 +633,28 @@
             }
         }
 
+        if (allowBackgroundActivityStarts) {
+            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
+            if (proc != null) {
+                proc.addAllowBackgroundActivityStartsToken(r);
+                // schedule removal of the whitelisting token after the timeout
+                removeAllowBackgroundActivityStartsServiceToken(proc, r,
+                        SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
+            }
+        }
         ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
         return cmp;
     }
 
+    private void removeAllowBackgroundActivityStartsServiceToken(ProcessRecord proc,
+            ServiceRecord r, int delayMillis) {
+        mAm.mHandler.postDelayed(() -> {
+            if (proc != null) {
+                proc.removeAllowBackgroundActivityStartsToken(r);
+            }
+        }, delayMillis);
+    }
+
     private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
             String callingPackage, int callingUid, Intent service, boolean callerFg,
             final int userId) {
@@ -710,7 +739,7 @@
 
     private void stopServiceLocked(ServiceRecord service) {
         if (service.delayed) {
-            // If service isn't actually running, but is is being held in the
+            // If service isn't actually running, but is being held in the
             // delayed list, then we need to keep it started but note that it
             // should be stopped once no longer delayed.
             if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
@@ -752,6 +781,9 @@
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
                 try {
+                    // immediately remove bg activity whitelisting token if there was one
+                    removeAllowBackgroundActivityStartsServiceToken(callerApp, r.record,
+                            0 /* delayMillis */);
                     stopServiceLocked(r.record);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
@@ -1654,6 +1686,10 @@
                 }
             }
 
+            if ((flags & Context.BIND_RESTRICT_ASSOCIATIONS) != 0) {
+                mAm.requireAllowedAssociationsLocked(s.appInfo.packageName);
+            }
+
             mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
                     callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
                     s.instanceName, s.processName);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4f21ee8..26141f7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -50,6 +50,7 @@
 import static android.os.IServiceManager.DUMP_FLAG_PROTO;
 import static android.os.Process.BLUETOOTH_UID;
 import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.NETWORK_STACK_UID;
 import static android.os.Process.NFC_UID;
 import static android.os.Process.PHONE_UID;
 import static android.os.Process.PROC_CHAR;
@@ -328,7 +329,7 @@
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.AlarmManagerInternal;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
 import com.android.server.DisplayThread;
@@ -2430,6 +2431,20 @@
     }
 
     /**
+     * Ensures that the given package name has an explicit set of allowed associations.
+     * If it does not, give it an empty set.
+     */
+    void requireAllowedAssociationsLocked(String packageName) {
+        if (mAllowedAssociations == null) {
+            mAllowedAssociations = new ArrayMap<>(
+                    SystemConfig.getInstance().getAllowedAssociations());
+        }
+        if (mAllowedAssociations.get(packageName) == null) {
+            mAllowedAssociations.put(packageName, new ArraySet<>());
+        }
+    }
+
+    /**
      * Returns true if the package {@code pkg1} running under user handle {@code uid1} is
      * allowed association with the package {@code pkg2} running under user handle {@code uid2}.
      * <p> If either of the packages are running as  part of the core system, then the
@@ -2437,7 +2452,8 @@
      */
     boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) {
         if (mAllowedAssociations == null) {
-            mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations();
+            mAllowedAssociations = new ArrayMap<>(
+                    SystemConfig.getInstance().getAllowedAssociations());
         }
         // Interactions with the system uid are always allowed, since that is the core system
         // that everyone needs to be able to interact with. Also allow reflexive associations
@@ -14343,6 +14359,7 @@
             case BLUETOOTH_UID:
             case NFC_UID:
             case SE_UID:
+            case NETWORK_STACK_UID:
                 isCallerSystem = true;
                 break;
             default:
@@ -19478,8 +19495,8 @@
 
         @Override
         public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
-                boolean fgRequired, String callingPackage, int userId)
-                throws TransactionTooLargeException {
+                boolean fgRequired, String callingPackage, int userId,
+                boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
             synchronized(ActivityManagerService.this) {
                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                         "startServiceInPackage: " + service + " type=" + resolvedType);
@@ -19487,7 +19504,8 @@
                 ComponentName res;
                 try {
                     res = mServices.startServiceLocked(null, service,
-                            resolvedType, -1, uid, fgRequired, callingPackage, userId);
+                            resolvedType, -1, uid, fgRequired, callingPackage, userId,
+                            allowBackgroundActivityStarts);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index b675d9d..98c9ad6 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -51,6 +51,7 @@
 
     public static final int FLAG_ACTIVITY_SENDER = 1 << 0;
     public static final int FLAG_BROADCAST_SENDER = 1 << 1;
+    public static final int FLAG_SERVICE_SENDER = 1 << 2;
 
     final PendingIntentController controller;
     final Key key;
@@ -62,6 +63,7 @@
     private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
     private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
     private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();
+    private ArraySet<IBinder> mAllowBgActivityStartsForServiceSender = new ArraySet<>();
 
     String stringName;
     String lastTagPrefix;
@@ -228,6 +230,9 @@
         if ((flags & FLAG_BROADCAST_SENDER) != 0) {
             mAllowBgActivityStartsForBroadcastSender.add(token);
         }
+        if ((flags & FLAG_SERVICE_SENDER) != 0) {
+            mAllowBgActivityStartsForServiceSender.add(token);
+        }
     }
 
     public void registerCancelListenerLocked(IResultReceiver receiver) {
@@ -426,7 +431,8 @@
                     try {
                         controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
                                 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
-                                key.packageName, userId);
+                                key.packageName, userId,
+                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken));
                     } catch (RuntimeException e) {
                         Slog.w(TAG, "Unable to send startService intent", e);
                     } catch (TransactionTooLargeException e) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 0d0824a..054c830 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1142,11 +1142,13 @@
     }
 
     void addAllowBackgroundActivityStartsToken(Binder entity) {
+        if (entity == null) return;
         mAllowBackgroundActivityStartsTokens.add(entity);
         mWindowProcessController.setAllowBackgroundActivityStarts(true);
     }
 
     void removeAllowBackgroundActivityStartsToken(Binder entity) {
+        if (entity == null) return;
         mAllowBackgroundActivityStartsTokens.remove(entity);
         mWindowProcessController.setAllowBackgroundActivityStarts(
                 !mAllowBackgroundActivityStartsTokens.isEmpty());
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
similarity index 94%
rename from services/core/java/com/android/server/AppOpsService.java
rename to services/core/java/com/android/server/appop/AppOpsService.java
index 3cdf09e..7ede6dc 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.appop;
 
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -35,8 +36,7 @@
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
-import android.app.AppOpsManager.HistoricalOpEntry;
-import android.app.AppOpsManager.HistoricalPackageOps;
+import android.app.AppOpsManager.HistoricalOps;
 import android.app.AppOpsManagerInternal;
 import android.app.AppOpsManagerInternal.CheckOpsDelegate;
 import android.content.BroadcastReceiver;
@@ -48,7 +48,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.media.AudioAttributes;
@@ -59,6 +58,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -95,6 +95,8 @@
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
 
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
 import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -213,6 +215,8 @@
     @VisibleForTesting
     final SparseArray<UidState> mUidStates = new SparseArray<>();
 
+    private final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
+
     long mLastRealtime;
 
     /*
@@ -654,6 +658,7 @@
 
     public void systemReady() {
         mConstants.startMonitoring(mContext.getContentResolver());
+        mHistoricalRegistry.systemReady(mContext.getContentResolver());
 
         synchronized (this) {
             boolean changed = false;
@@ -1012,113 +1017,99 @@
     }
 
     @Override
-    public @Nullable ParceledListSlice getAllHistoricalPackagesOps(@Nullable String[] opNames,
-            long beginTimeMillis, long endTimeMillis) {
+    public void getHistoricalOps(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+                "uid must be " + Process.INVALID_UID + " or non negative");
         Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
                 "beginTimeMillis must be non negative and lesser than endTimeMillis");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
+        checkValidOpsOrNull(opNames);
 
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), "getAllHistoricalPackagesOps");
+                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
 
-        ArrayList<HistoricalPackageOps> historicalPackageOpsList = null;
-
-        final int uidStateCount = mUidStates.size();
-        for (int i = 0; i < uidStateCount; i++) {
-            final UidState uidState = mUidStates.valueAt(i);
-            if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
-                continue;
-            }
-            final ArrayMap<String, Ops> packages = uidState.pkgOps;
-            final int packageCount = packages.size();
-            for (int j = 0; j < packageCount; j++) {
-                final Ops pkgOps = packages.valueAt(j);
-                final AppOpsManager.HistoricalPackageOps historicalPackageOps =
-                        createHistoricalPackageOps(uidState.uid, pkgOps, opNames,
-                                beginTimeMillis, endTimeMillis);
-                if (historicalPackageOps != null) {
-                    if (historicalPackageOpsList == null) {
-                        historicalPackageOpsList = new ArrayList<>();
-                    }
-                    historicalPackageOpsList.add(historicalPackageOps);
-                }
-            }
+        if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
+            // TODO (bug:122218838): Remove once the feature fully enabled.
+            getHistoricalPackagesOpsCompat(uid, packageName, opNames, beginTimeMillis,
+                    endTimeMillis, callback);
+        } else {
+            // Must not hold the appops lock
+            mHistoricalRegistry.getHistoricalOps(uid, packageName, opNames,
+                    beginTimeMillis, endTimeMillis, callback);
         }
-
-        if (historicalPackageOpsList == null) {
-            return null;
-        }
-
-        return new ParceledListSlice<>(historicalPackageOpsList);
     }
 
-    private static @Nullable HistoricalPackageOps createHistoricalPackageOps(int uid,
-            @Nullable Ops pkgOps, @Nullable String[] opNames, long beginTimeMillis,
-            long endTimeMillis) {
-        // TODO: Implement historical data collection
-        if (pkgOps == null) {
-            return null;
+    private void getHistoricalPackagesOpsCompat(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        synchronized (AppOpsService.this) {
+            final HistoricalOps ops = new HistoricalOps(beginTimeMillis, endTimeMillis);
+            if (opNames == null) {
+                opNames = AppOpsManager.getOpStrs();
+            }
+            final int uidStateCount = mUidStates.size();
+            for (int uidIdx = 0; uidIdx < uidStateCount; uidIdx++) {
+                final UidState uidState = mUidStates.valueAt(uidIdx);
+                if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()
+                        || (uid != Process.INVALID_UID && uid != uidState.uid)) {
+                    continue;
+                }
+                final ArrayMap<String, Ops> packages = uidState.pkgOps;
+                final int packageCount = packages.size();
+                for (int pkgIdx = 0; pkgIdx < packageCount; pkgIdx++) {
+                    final Ops pkgOps = packages.valueAt(pkgIdx);
+                    if (packageName != null && !packageName.equals(pkgOps.packageName)) {
+                        continue;
+                    }
+                    final int opCount = opNames.length;
+                    for (int opIdx = 0; opIdx < opCount; opIdx++) {
+                        final String opName = opNames[opIdx];
+                        if (!ArrayUtils.contains(opNames, opName)) {
+                            continue;
+                        }
+                        final int opCode = AppOpsManager.strOpToOp(opName);
+                        final Op op = pkgOps.get(opCode);
+                        if (op == null) {
+                            continue;
+                        }
+                        final int stateCount = AppOpsManager._NUM_UID_STATE;
+                        for (int stateIdx = 0; stateIdx < stateCount; stateIdx++) {
+                            if (op.rejectTime[stateIdx] != 0) {
+                                ops.increaseRejectCount(opCode, uidState.uid,
+                                        pkgOps.packageName, stateIdx, 1);
+                            } else if (op.time[stateIdx] != 0) {
+                                ops.increaseAccessCount(opCode, uidState.uid,
+                                        pkgOps.packageName, stateIdx, 1);
+                            }
+                        }
+                    }
+                }
+            }
+            final Bundle payload = new Bundle();
+            payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, ops);
+            callback.sendResult(payload);
         }
-
-        final HistoricalPackageOps historicalPackageOps = new HistoricalPackageOps(uid,
-                pkgOps.packageName);
-
-        if (opNames == null) {
-            opNames = AppOpsManager.getOpStrs();
-        }
-        for (String opName : opNames) {
-            addHistoricOpEntry(AppOpsManager.strOpToOp(opName), pkgOps, historicalPackageOps);
-        }
-
-        return historicalPackageOps;
     }
 
     @Override
-    public @Nullable HistoricalPackageOps getHistoricalPackagesOps(int uid,
-            @NonNull String packageName, @Nullable String[] opNames,
-            long beginTimeMillis, long endTimeMillis) {
-        Preconditions.checkNotNull(packageName,
-                "packageName cannot be null");
+    public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+                "uid must be " + Process.INVALID_UID + " or non negative");
         Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
                 "beginTimeMillis must be non negative and lesser than endTimeMillis");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
+        checkValidOpsOrNull(opNames);
 
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalPackagesOps");
+                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
 
-        final String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return null;
-        }
-
-        // TODO: Implement historical data collection
-        final Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
-                false /* uidMismatchExpected */);
-        return createHistoricalPackageOps(uid, pkgOps, opNames, beginTimeMillis, endTimeMillis);
-    }
-
-    private static void addHistoricOpEntry(int opCode, @NonNull Ops ops,
-            @NonNull HistoricalPackageOps outHistoricalPackageOps) {
-        final Op op = ops.get(opCode);
-        if (op == null) {
-            return;
-        }
-
-        final HistoricalOpEntry historicalOpEntry = new HistoricalOpEntry(opCode);
-
-        // TODO: Keep per UID state duration
-        for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
-            final int acceptCount;
-            final int rejectCount;
-            if (op.rejectTime[uidState] == 0) {
-                acceptCount = 1;
-                rejectCount = 0;
-            } else {
-                acceptCount = 0;
-                rejectCount = 1;
-            }
-            historicalOpEntry.addEntry(uidState, acceptCount, rejectCount, 0);
-        }
-
-        outHistoricalPackageOps.addEntry(historicalOpEntry);
+        // Must not hold the appops lock
+        mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNames,
+                beginTimeMillis, endTimeMillis, callback);
     }
 
     @Override
@@ -1884,6 +1875,8 @@
                             + packageName);
                     op.rejectTime[uidState.state] = System.currentTimeMillis();
                     scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
                     return uidMode;
                 }
             } else {
@@ -1895,12 +1888,16 @@
                             + packageName);
                     op.rejectTime[uidState.state] = System.currentTimeMillis();
                     scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
                     return mode;
                 }
             }
             if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
                     + " package " + packageName);
             op.time[uidState.state] = System.currentTimeMillis();
+            mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
+                    uidState.state);
             op.rejectTime[uidState.state] = 0;
             op.proxyUid = proxyUid;
             op.proxyPackageName = proxyPackageName;
@@ -2035,6 +2032,8 @@
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + resolvedPackageName);
                     op.rejectTime[uidState.state] = System.currentTimeMillis();
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
                     return uidMode;
                 }
             } else {
@@ -2046,6 +2045,8 @@
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + resolvedPackageName);
                     op.rejectTime[uidState.state] = System.currentTimeMillis();
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
                     return mode;
                 }
             }
@@ -2054,6 +2055,8 @@
             if (op.startNesting == 0) {
                 op.startRealtime = SystemClock.elapsedRealtime();
                 op.time[uidState.state] = System.currentTimeMillis();
+                mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
+                        uidState.state);
                 op.rejectTime[uidState.state] = 0;
                 op.duration = -1;
                 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
@@ -2216,6 +2219,8 @@
         if (op.startNesting <= 1 || finishNested) {
             if (op.startNesting == 1 || finishNested) {
                 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
+                mHistoricalRegistry.increaseOpAccessDuration(op.op, op.uid, op.packageName,
+                        op.uidState.state, op.duration);
                 op.time[op.uidState.state] = System.currentTimeMillis();
             } else {
                 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
@@ -2344,7 +2349,7 @@
                         ApplicationInfo appInfo = ActivityThread.getPackageManager()
                                 .getApplicationInfo(packageName,
                                         PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                                         UserHandle.getUserId(uid));
                         if (appInfo != null) {
                             pkgUid = appInfo.uid;
@@ -3391,6 +3396,8 @@
         pw.println("    Limit output to data associated with the given app op mode.");
         pw.println("  --package [PACKAGE]");
         pw.println("    Limit output to data associated with the given package name.");
+        pw.println("  --watchers");
+        pw.println("    Only output the watcher sections.");
     }
 
     private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
@@ -3425,10 +3432,11 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
 
-        int dumpOp = -1;
+        int dumpOp = OP_NONE;
         String dumpPackage = null;
-        int dumpUid = -1;
+        int dumpUid = Process.INVALID_UID;
         int dumpMode = -1;
+        boolean dumpWatchers = false;
 
         if (args != null) {
             for (int i=0; i<args.length; i++) {
@@ -3476,6 +3484,8 @@
                     if (dumpMode < 0) {
                         return;
                     }
+                } else if ("--watchers".equals(arg)) {
+                    dumpWatchers = true;
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                     pw.println("Unknown option: " + arg);
                     return;
@@ -3496,7 +3506,8 @@
             final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
             final Date date = new Date();
             boolean needSep = false;
-            if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
+            if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null
+                    && !dumpWatchers) {
                 pw.println("  Profile owners:");
                 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
                     pw.print("    User #");
@@ -3517,7 +3528,7 @@
                     ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
                     for (int j=0; j<callbacks.size(); j++) {
                         final ModeCallback cb = callbacks.valueAt(j);
-                        if (dumpPackage != null && cb.mWatchingUid >= 0
+                        if (dumpPackage != null
                                 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
                             continue;
                         }
@@ -3561,7 +3572,7 @@
                 boolean printedHeader = false;
                 for (int i=0; i<mModeWatchers.size(); i++) {
                     final ModeCallback cb = mModeWatchers.valueAt(i);
-                    if (dumpPackage != null && cb.mWatchingUid >= 0
+                    if (dumpPackage != null
                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
                         continue;
                     }
@@ -3587,7 +3598,7 @@
                     if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
                         continue;
                     }
-                    if (dumpPackage != null && cb.mWatchingUid >= 0
+                    if (dumpPackage != null
                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
                         continue;
                     }
@@ -3627,7 +3638,7 @@
                     if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
                         continue;
                     }
-                    if (dumpPackage != null && cb.mWatchingUid >= 0
+                    if (dumpPackage != null
                             && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
                         continue;
                     }
@@ -3655,7 +3666,7 @@
                     pw.println(cb);
                 }
             }
-            if (mClients.size() > 0 && dumpMode < 0) {
+            if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers) {
                 needSep = true;
                 boolean printedHeader = false;
                 for (int i=0; i<mClients.size(); i++) {
@@ -3692,7 +3703,7 @@
                 }
             }
             if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
-                    && dumpMode < 0) {
+                    && dumpMode < 0 && !dumpWatchers) {
                 boolean printedHeader = false;
                 for (int o=0; o<mAudioRestrictions.size(); o++) {
                     final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
@@ -3725,6 +3736,9 @@
                 final SparseIntArray opModes = uidState.opModes;
                 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
 
+                if (dumpWatchers) {
+                    continue;
+                }
                 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
                     boolean hasOp = dumpOp < 0 || (uidState.opModes != null
                             && uidState.opModes.indexOfKey(dumpOp) >= 0);
@@ -3739,8 +3753,8 @@
                     }
                     if (pkgOps != null) {
                         for (int pkgi = 0;
-                                (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
-                                pkgi++) {
+                                 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
+                                 pkgi++) {
                             Ops ops = pkgOps.valueAt(pkgi);
                             if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
                                 hasOp = true;
@@ -3880,18 +3894,34 @@
             for (int i = 0; i < userRestrictionCount; i++) {
                 IBinder token = mOpUserRestrictions.keyAt(i);
                 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
-                pw.println("  User restrictions for token " + token + ":");
+                boolean printedTokenHeader = false;
+
+                if (dumpMode >= 0 || dumpWatchers) {
+                    continue;
+                }
 
                 final int restrictionCount = restrictionState.perUserRestrictions != null
                         ? restrictionState.perUserRestrictions.size() : 0;
-                if (restrictionCount > 0) {
-                    pw.println("      Restricted ops:");
+                if (restrictionCount > 0 && dumpPackage == null) {
+                    boolean printedOpsHeader = false;
                     for (int j = 0; j < restrictionCount; j++) {
                         int userId = restrictionState.perUserRestrictions.keyAt(j);
                         boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
                         if (restrictedOps == null) {
                             continue;
                         }
+                        if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
+                                || !restrictedOps[dumpOp])) {
+                            continue;
+                        }
+                        if (!printedTokenHeader) {
+                            pw.println("  User restrictions for token " + token + ":");
+                            printedTokenHeader = true;
+                        }
+                        if (!printedOpsHeader) {
+                            pw.println("      Restricted ops:");
+                            printedOpsHeader = true;
+                        }
                         StringBuilder restrictedOpsValue = new StringBuilder();
                         restrictedOpsValue.append("[");
                         final int restrictedOpCount = restrictedOps.length;
@@ -3911,17 +3941,46 @@
 
                 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
                         ? restrictionState.perUserExcludedPackages.size() : 0;
-                if (excludedPackageCount > 0) {
-                    pw.println("      Excluded packages:");
+                if (excludedPackageCount > 0 && dumpOp < 0) {
+                    boolean printedPackagesHeader = false;
                     for (int j = 0; j < excludedPackageCount; j++) {
                         int userId = restrictionState.perUserExcludedPackages.keyAt(j);
                         String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
+                        if (packageNames == null) {
+                            continue;
+                        }
+                        boolean hasPackage;
+                        if (dumpPackage != null) {
+                            hasPackage = false;
+                            for (String pkg : packageNames) {
+                                if (dumpPackage.equals(pkg)) {
+                                    hasPackage = true;
+                                    break;
+                                }
+                            }
+                        } else {
+                            hasPackage = true;
+                        }
+                        if (!hasPackage) {
+                            continue;
+                        }
+                        if (!printedTokenHeader) {
+                            pw.println("  User restrictions for token " + token + ":");
+                            printedTokenHeader = true;
+                        }
+                        if (!printedPackagesHeader) {
+                            pw.println("      Excluded packages:");
+                            printedPackagesHeader = true;
+                        }
                         pw.print("        "); pw.print("user: "); pw.print(userId);
                                 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
                     }
                 }
             }
         }
+
+        // Must not hold the appops lock
+        mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpOp);
     }
 
     private static final class Restriction {
@@ -4042,6 +4101,47 @@
         return false;
     }
 
+    @Override
+    public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
+            long baseSnapshotInterval, int compressionStep) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "setHistoryParameters");
+        // Must not hold the appops lock
+        mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+    }
+
+    @Override
+    public void offsetHistory(long offsetMillis) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "offsetHistory");
+        // Must not hold the appops lock
+        mHistoricalRegistry.offsetHistory(offsetMillis);
+    }
+
+    @Override
+    public void addHistoricalOps(HistoricalOps ops) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "addHistoricalOps");
+        // Must not hold the appops lock
+        mHistoricalRegistry.addHistoricalOps(ops);
+    }
+
+    @Override
+    public void resetHistoryParameters() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "resetHistoryParameters");
+        // Must not hold the appops lock
+        mHistoricalRegistry.resetHistoryParameters();
+    }
+
+    @Override
+    public void clearHistory() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "clearHistory");
+        // Must not hold the appops lock
+        mHistoricalRegistry.clearHistory();
+    }
+
     private void removeUidsForUserLocked(int userHandle) {
         for (int i = mUidStates.size() - 1; i >= 0; --i) {
             final int uid = mUidStates.keyAt(i);
@@ -4112,6 +4212,16 @@
         return packageNames;
     }
 
+    private static void checkValidOpsOrNull(String[] opNames) {
+        if (opNames != null) {
+            for (String opName : opNames) {
+                if (AppOpsManager.strOpToOp(opName) == AppOpsManager.OP_NONE) {
+                    throw new IllegalArgumentException("Unknown op: " + opName);
+                }
+            }
+        }
+    }
+
     private final class ClientRestrictionState implements DeathRecipient {
         private final IBinder token;
         SparseArray<boolean[]> perUserRestrictions;
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
new file mode 100644
index 0000000..8d7811f
--- /dev/null
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -0,0 +1,1495 @@
+/*
+ * 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.appop;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.HistoricalMode;
+import android.app.AppOpsManager.HistoricalOp;
+import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManager.HistoricalPackageOps;
+import android.app.AppOpsManager.HistoricalUidOps;
+import android.app.AppOpsManager.UidState;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.TimeUtils;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.AtomicDirectory;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class managers historical app op state. This includes reading, persistence,
+ * accounting, querying.
+ * <p>
+ * The history is kept forever in multiple files. Each file time contains the
+ * relative offset from the current time which time is encoded in the file name.
+ * The files contain historical app op state snapshots which have times that
+ * are relative to the time of the container file.
+ *
+ * The data in the files are stored in a logarithmic fashion where where every
+ * subsequent file would contain data for ten times longer interval with ten
+ * times more time distance between snapshots. Hence, the more time passes
+ * the lesser the fidelity.
+ * <p>
+ * For example, the first file would contain data for 1 days with snapshots
+ * every 0.1 days, the next file would contain data for the period 1 to 10
+ * days with snapshots every 1 days, and so on.
+ * <p>
+ * THREADING AND LOCKING: Reported ops must be processed as quickly as possible.
+ * We keep ops pending to be persisted in memory and write to disk on a background
+ * thread. Hence, methods that report op changes are locking only the in memory
+ * state guarded by the mInMemoryLock which happens to be the app ops service lock
+ * avoiding a lock addition on the critical path. When a query comes we need to
+ * evaluate it based off both in memory and on disk state. This means they need to
+ * be frozen with respect to each other and not change from the querying caller's
+ * perspective. To achieve this we add a dedicated mOnDiskLock to guard the on
+ * disk state. To have fast critical path we need to limit the locking of the
+ * mInMemoryLock, thus for operations that touch in memory and on disk state one
+ * must grab first the mOnDiskLock and then the mInMemoryLock and limit the
+ * in memory lock to extraction of relevant data. Locking order is critical to
+ * avoid deadlocks. The convention is that xxxDLocked suffix means the method
+ * must be called with the mOnDiskLock lock, xxxMLocked suffix means the method
+ * must be called with the mInMemoryLock, xxxDMLocked suffix means the method
+ * must be called with the mOnDiskLock and mInMemoryLock locks acquired in that
+ * exact order.
+ */
+// TODO (bug:122218838): Make sure we handle start of epoch time
+// TODO (bug:122218838): Validate changed time is handled correctly
+final class HistoricalRegistry {
+    private static final boolean DEBUG = false;
+
+    private static final String LOG_TAG = HistoricalRegistry.class.getSimpleName();
+
+    private static final String PARAMETER_DELIMITER = ",";
+    private static final String PARAMETER_ASSIGNMENT = "=";
+
+    @GuardedBy("mLock")
+    private @NonNull LinkedList<HistoricalOps> mPendingWrites = new LinkedList<>();
+
+    // Lock for read/write access to on disk state
+    private final Object mOnDiskLock = new Object();
+
+    //Lock for read/write access to in memory state
+    private final @NonNull Object mInMemoryLock;
+
+    private static final int MSG_WRITE_PENDING_HISTORY = 1;
+
+    // See mMode
+    private static final int DEFAULT_MODE = AppOpsManager.HISTORICAL_MODE_DISABLED;
+
+    // See mBaseSnapshotInterval
+    private static final long DEFAULT_SNAPSHOT_INTERVAL_MILLIS = TimeUnit.MINUTES.toMillis(15);
+
+    // See mIntervalCompressionMultiplier
+    private static final long DEFAULT_COMPRESSION_STEP = 10;
+
+    /**
+     * Whether history is enabled.
+     */
+    @GuardedBy("mInMemoryLock")
+    private int mMode = AppOpsManager.HISTORICAL_MODE_DISABLED;
+
+    /**
+     * This granularity has been chosen to allow clean delineation for intervals
+     * humans understand, 15 min, 60, min, a day, a week, a month (30 days).
+     */
+    @GuardedBy("mInMemoryLock")
+    private long mBaseSnapshotInterval = DEFAULT_SNAPSHOT_INTERVAL_MILLIS;
+
+    /**
+     * The compression between steps. Each subsequent step is this much longer
+     * in terms of duration and each snapshot is this much more apart from the
+     * previous step.
+     */
+    @GuardedBy("mInMemoryLock")
+    private long mIntervalCompressionMultiplier = DEFAULT_COMPRESSION_STEP;
+
+    // The current ops to which to add statistics.
+    @GuardedBy("mInMemoryLock")
+    private @Nullable HistoricalOps mCurrentHistoricalOps;
+
+    // The time we should write the next snapshot.
+    @GuardedBy("mInMemoryLock")
+    private long mNextPersistDueTimeMillis;
+
+    // How much to offset the history on the next write.
+    @GuardedBy("mInMemoryLock")
+    private long mPendingHistoryOffsetMillis;
+
+    // Object managing persistence (read/write)
+    @GuardedBy("mOnDiskLock")
+    private Persistence mPersistence = new Persistence(mBaseSnapshotInterval,
+            mIntervalCompressionMultiplier);
+
+    HistoricalRegistry(@NonNull Object lock) {
+        mInMemoryLock = lock;
+        if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) {
+            synchronized (mInMemoryLock) {
+                // When starting always adjust history to now.
+                mPendingHistoryOffsetMillis = System.currentTimeMillis()
+                        - mPersistence.getLastPersistTimeMillisDLocked();
+            }
+        }
+    }
+
+    void systemReady(@NonNull ContentResolver resolver) {
+        updateParametersFromSetting(resolver);
+        final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
+        resolver.registerContentObserver(uri, false, new ContentObserver(
+                FgThread.getHandler()) {
+            @Override
+            public void onChange(boolean selfChange) {
+                updateParametersFromSetting(resolver);
+            }
+        });
+    }
+
+    private void updateParametersFromSetting(@NonNull ContentResolver resolver) {
+        final String setting = Settings.Global.getString(resolver,
+                Settings.Global.APPOP_HISTORY_PARAMETERS);
+        if (setting == null) {
+            return;
+        }
+        String modeValue = null;
+        String baseSnapshotIntervalValue = null;
+        String intervalMultiplierValue = null;
+        final String[] parameters = setting.split(PARAMETER_DELIMITER);
+        for (String parameter : parameters) {
+            final String[] parts = parameter.split(PARAMETER_ASSIGNMENT);
+            if (parts.length == 2) {
+                final String key = parts[0].trim();
+                switch (key) {
+                    case Settings.Global.APPOP_HISTORY_MODE: {
+                        modeValue = parts[1].trim();
+                    } break;
+                    case Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS: {
+                        baseSnapshotIntervalValue = parts[1].trim();
+                    } break;
+                    case Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER: {
+                        intervalMultiplierValue = parts[1].trim();
+                    } break;
+                    default: {
+                        Slog.w(LOG_TAG, "Unknown parameter: " + parameter);
+                    }
+                }
+            }
+        }
+        if (modeValue != null && baseSnapshotIntervalValue != null
+                && intervalMultiplierValue != null) {
+            try {
+                final int mode = AppOpsManager.parseHistoricalMode(modeValue);
+                final long baseSnapshotInterval = Long.parseLong(baseSnapshotIntervalValue);
+                final int intervalCompressionMultiplier = Integer.parseInt(intervalMultiplierValue);
+                setHistoryParameters(mode, baseSnapshotInterval,intervalCompressionMultiplier);
+                return;
+            } catch (NumberFormatException ignored) {}
+        }
+        Slog.w(LOG_TAG, "Bad value for" + Settings.Global.APPOP_HISTORY_PARAMETERS
+                + "=" + setting + " resetting!");
+    }
+
+    void dump(String prefix, PrintWriter pw,  int filterUid,
+            String filterPackage, int filterOp) {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                pw.println();
+                pw.print(prefix);
+                pw.print("History:");
+
+                pw.print("  mode=");
+                pw.println(AppOpsManager.historicalModeToString(mMode));
+
+                final StringDumpVisitor visitor = new StringDumpVisitor(prefix + "  ",
+                        pw, filterUid, filterPackage, filterOp);
+                final long nowMillis = System.currentTimeMillis();
+
+                // Dump in memory state first
+                final HistoricalOps currentOps = getUpdatedPendingHistoricalOpsMLocked(
+                        nowMillis);
+                makeRelativeToEpochStart(currentOps, nowMillis);
+                currentOps.accept(visitor);
+
+                final List<HistoricalOps> ops = mPersistence.readHistoryDLocked();
+                if (ops != null) {
+                    // TODO (bug:122218838): Make sure this is properly dumped
+                    final long remainingToFillBatchMillis = mNextPersistDueTimeMillis
+                            - nowMillis - mBaseSnapshotInterval;
+                    final int opCount = ops.size();
+                    for (int i = 0; i < opCount; i++) {
+                        final HistoricalOps op = ops.get(i);
+                        op.offsetBeginAndEndTime(remainingToFillBatchMillis);
+                        makeRelativeToEpochStart(op, nowMillis);
+                        op.accept(visitor);
+                    }
+                } else {
+                    pw.println("  Empty");
+                }
+            }
+        }
+    }
+
+    @HistoricalMode int getMode() {
+        synchronized (mInMemoryLock) {
+            return mMode;
+        }
+    }
+
+    @Nullable void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
+        mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
+                beginTimeMillis, endTimeMillis);
+        final Bundle payload = new Bundle();
+        payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+        callback.sendResult(payload);
+    }
+
+    @Nullable void getHistoricalOps(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        final long currentTimeMillis = System.currentTimeMillis();
+        if (endTimeMillis == Long.MAX_VALUE) {
+            endTimeMillis = currentTimeMillis;
+        }
+
+        // Argument times are based off epoch start while our internal store is
+        // based off now, so take this into account.
+        final long inMemoryAdjBeginTimeMillis = Math.max(currentTimeMillis - endTimeMillis, 0);
+        final long inMemoryAdjEndTimeMillis = Math.max(currentTimeMillis - beginTimeMillis, 0);
+        final HistoricalOps result = new HistoricalOps(inMemoryAdjBeginTimeMillis,
+                inMemoryAdjEndTimeMillis);
+
+        synchronized (mOnDiskLock) {
+            final List<HistoricalOps> pendingWrites;
+            final HistoricalOps currentOps;
+            synchronized (mInMemoryLock) {
+                currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
+                if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
+                        || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
+                    // Some of the current batch falls into the query, so extract that.
+                    final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
+                    currentOpsCopy.filter(uid, packageName, opNames, inMemoryAdjBeginTimeMillis,
+                            inMemoryAdjEndTimeMillis);
+                    result.merge(currentOpsCopy);
+                }
+                pendingWrites = new ArrayList<>(mPendingWrites);
+                mPendingWrites.clear();
+            }
+
+            // If the query was only for in-memory state - done.
+            if (inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis()) {
+                // If there is a write in flight we need to force it now
+                persistPendingHistory(pendingWrites);
+                // Collect persisted state.
+                final long onDiskAndInMemoryOffsetMillis = currentTimeMillis
+                        - mNextPersistDueTimeMillis + mBaseSnapshotInterval;
+                final long onDiskAdjBeginTimeMillis = Math.max(inMemoryAdjBeginTimeMillis
+                        - onDiskAndInMemoryOffsetMillis, 0);
+                final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
+                        - onDiskAndInMemoryOffsetMillis, 0);
+                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
+                        onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis);
+            }
+
+            // Rebase the result time to be since epoch.
+            result.setBeginAndEndTime(beginTimeMillis, endTimeMillis);
+
+            // Send back the result.
+            final Bundle payload = new Bundle();
+            payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+            callback.sendResult(payload);
+        }
+    }
+
+    void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
+            @UidState int uidState) {
+        synchronized (mInMemoryLock) {
+            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+                        .increaseAccessCount(op, uid, packageName, uidState, 1);
+
+            }
+        }
+    }
+
+    void incrementOpRejected(int op, int uid, @NonNull String packageName,
+            @UidState int uidState) {
+        synchronized (mInMemoryLock) {
+            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+                        .increaseRejectCount(op, uid, packageName, uidState, 1);
+            }
+        }
+    }
+
+    void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
+            @UidState int uidState, long increment) {
+        synchronized (mInMemoryLock) {
+            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+                        .increaseAccessDuration(op, uid, packageName, uidState, increment);
+            }
+        }
+    }
+
+    void setHistoryParameters(@HistoricalMode int mode,
+            long baseSnapshotInterval, long intervalCompressionMultiplier) {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                boolean resampleHistory = false;
+                Slog.i(LOG_TAG, "New history parameters: mode:"
+                        + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:"
+                        + baseSnapshotInterval + " intervalCompressionMultiplier:"
+                        + intervalCompressionMultiplier);
+                if (mMode != mode) {
+                    mMode = mode;
+                    if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) {
+                        clearHistoryOnDiskLocked();
+                    }
+                }
+                if (mBaseSnapshotInterval != baseSnapshotInterval) {
+                    mBaseSnapshotInterval = baseSnapshotInterval;
+                    resampleHistory = true;
+                }
+                if (mIntervalCompressionMultiplier != intervalCompressionMultiplier) {
+                    mIntervalCompressionMultiplier = intervalCompressionMultiplier;
+                    resampleHistory = true;
+                }
+                if (resampleHistory) {
+                    resampleHistoryOnDiskInMemoryDMLocked(0);
+                }
+            }
+        }
+    }
+
+    void offsetHistory(long offsetMillis) {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                final List<HistoricalOps> history = mPersistence.readHistoryDLocked();
+                clearHistory();
+                if (history != null) {
+                    final int historySize = history.size();
+                    for (int i = 0; i < historySize; i++) {
+                        final HistoricalOps ops = history.get(i);
+                        ops.offsetBeginAndEndTime(offsetMillis);
+                    }
+                    if (offsetMillis < 0) {
+                        pruneFutureOps(history);
+                    }
+                    mPersistence.persistHistoricalOpsDLocked(history);
+                }
+            }
+        }
+    }
+
+    void addHistoricalOps(HistoricalOps ops) {
+        final List<HistoricalOps> pendingWrites;
+        synchronized (mInMemoryLock) {
+            // The history files start from mBaseSnapshotInterval - take this into account.
+            ops.offsetBeginAndEndTime(mBaseSnapshotInterval);
+            mPendingWrites.offerFirst(ops);
+            pendingWrites = new ArrayList<>(mPendingWrites);
+            mPendingWrites.clear();
+        }
+        persistPendingHistory(pendingWrites);
+    }
+
+    private void resampleHistoryOnDiskInMemoryDMLocked(long offsetMillis) {
+        mPersistence = new Persistence(mBaseSnapshotInterval, mIntervalCompressionMultiplier);
+        offsetHistory(offsetMillis);
+    }
+
+    void resetHistoryParameters() {
+        setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS,
+                DEFAULT_COMPRESSION_STEP);
+    }
+
+    void clearHistory() {
+        synchronized (mOnDiskLock) {
+            clearHistoryOnDiskLocked();
+        }
+    }
+
+    private void clearHistoryOnDiskLocked() {
+        BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
+        synchronized (mInMemoryLock) {
+            mCurrentHistoricalOps = null;
+            mNextPersistDueTimeMillis = System.currentTimeMillis();
+            mPendingWrites.clear();
+        }
+        mPersistence.clearHistoryDLocked();
+    }
+
+    private @NonNull HistoricalOps getUpdatedPendingHistoricalOpsMLocked(long now) {
+        if (mCurrentHistoricalOps != null) {
+            final long remainingTimeMillis = mNextPersistDueTimeMillis - now;
+            if (remainingTimeMillis > mBaseSnapshotInterval) {
+                // If time went backwards we need to push history to the future with the
+                // overflow over our snapshot interval. If time went forward do nothing
+                // as we would naturally push history into the past on the next write.
+                mPendingHistoryOffsetMillis = remainingTimeMillis - mBaseSnapshotInterval;
+            }
+            final long elapsedTimeMillis = mBaseSnapshotInterval - remainingTimeMillis;
+            mCurrentHistoricalOps.setEndTime(elapsedTimeMillis);
+            if (remainingTimeMillis > 0) {
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "Returning current in-memory state");
+                }
+                return mCurrentHistoricalOps;
+            }
+            if (mCurrentHistoricalOps.isEmpty()) {
+                mCurrentHistoricalOps.setBeginAndEndTime(0, 0);
+                mNextPersistDueTimeMillis = now + mBaseSnapshotInterval;
+                return mCurrentHistoricalOps;
+            }
+            // The current batch is full, so persist taking into account overdue persist time.
+            mCurrentHistoricalOps.offsetBeginAndEndTime(mBaseSnapshotInterval);
+            mCurrentHistoricalOps.setBeginTime(mCurrentHistoricalOps.getEndTimeMillis()
+                    - mBaseSnapshotInterval);
+            final long overdueTimeMillis = Math.abs(remainingTimeMillis);
+            mCurrentHistoricalOps.offsetBeginAndEndTime(overdueTimeMillis);
+            schedulePersistHistoricalOpsMLocked(mCurrentHistoricalOps);
+        }
+        // The current batch is in the future, i.e. not complete yet.
+        mCurrentHistoricalOps = new HistoricalOps(0, 0);
+        mNextPersistDueTimeMillis = now + mBaseSnapshotInterval;
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "Returning new in-memory state");
+        }
+        return mCurrentHistoricalOps;
+    }
+
+    private void persistPendingHistory() {
+        final List<HistoricalOps> pendingWrites;
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                pendingWrites = new ArrayList<>(mPendingWrites);
+                mPendingWrites.clear();
+                if (mPendingHistoryOffsetMillis != 0) {
+                    resampleHistoryOnDiskInMemoryDMLocked(mPendingHistoryOffsetMillis);
+                    mPendingHistoryOffsetMillis = 0;
+                }
+            }
+            persistPendingHistory(pendingWrites);
+        }
+    }
+    private void persistPendingHistory(@NonNull List<HistoricalOps> pendingWrites) {
+        synchronized (mOnDiskLock) {
+            BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
+            if (pendingWrites.isEmpty()) {
+                return;
+            }
+            final int opCount = pendingWrites.size();
+            // Pending writes are offset relative to each other, so take this
+            // into account to persist everything in one shot - single write.
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOps current = pendingWrites.get(i);
+                if (i > 0) {
+                    final HistoricalOps previous = pendingWrites.get(i - 1);
+                    current.offsetBeginAndEndTime(previous.getBeginTimeMillis());
+                }
+            }
+            mPersistence.persistHistoricalOpsDLocked(pendingWrites);
+        }
+    }
+
+    private void schedulePersistHistoricalOpsMLocked(@NonNull HistoricalOps ops) {
+        final Message message = PooledLambda.obtainMessage(
+                HistoricalRegistry::persistPendingHistory, HistoricalRegistry.this);
+        message.what = MSG_WRITE_PENDING_HISTORY;
+        BackgroundThread.getHandler().sendMessage(message);
+        mPendingWrites.offerFirst(ops);
+    }
+
+    private static void makeRelativeToEpochStart(@NonNull HistoricalOps ops, long nowMillis) {
+        ops.setBeginAndEndTime(nowMillis - ops.getEndTimeMillis(),
+                nowMillis- ops.getBeginTimeMillis());
+    }
+
+    private void pruneFutureOps(@NonNull List<HistoricalOps> ops) {
+        final int opCount = ops.size();
+        for (int i = opCount - 1; i >= 0; i--) {
+            final HistoricalOps op = ops.get(i);
+            if (op.getEndTimeMillis() <= mBaseSnapshotInterval) {
+                ops.remove(i);
+            } else if (op.getBeginTimeMillis() < mBaseSnapshotInterval) {
+                final double filterScale = (double) (op.getEndTimeMillis() - mBaseSnapshotInterval)
+                        / (double) op.getDurationMillis();
+                Persistence.spliceFromBeginning(op, filterScale);
+            }
+        }
+    }
+
+    private static final class Persistence {
+        private static final boolean DEBUG = false;
+
+        private static final String LOG_TAG = Persistence.class.getSimpleName();
+
+        private static final String HISTORY_FILE_SUFFIX = ".xml";
+
+        private static final String TAG_HISTORY = "history";
+        private static final String TAG_OPS = "ops";
+        private static final String TAG_UID = "uid";
+        private static final String TAG_PACKAGE = "package";
+        private static final String TAG_OP = "op";
+        private static final String TAG_STATE = "state";
+
+        private static final String ATTR_VERSION = "version";
+        private static final String ATTR_NAME = "name";
+        private static final String ATTR_ACCESS_COUNT = "accessCount";
+        private static final String ATTR_REJECT_COUNT = "rejectCount";
+        private static final String ATTR_ACCESS_DURATION = "accessDuration";
+        private static final String ATTR_BEGIN_TIME = "beginTime";
+        private static final String ATTR_END_TIME = "endTime";
+        private static final String ATTR_OVERFLOW = "overflow";
+
+        private static final int CURRENT_VERSION = 1;
+
+        private final long mBaseSnapshotInterval;
+        private final long mIntervalCompressionMultiplier;
+
+        Persistence(long baseSnapshotInterval, long intervalCompressionMultiplier) {
+            mBaseSnapshotInterval = baseSnapshotInterval;
+            mIntervalCompressionMultiplier = intervalCompressionMultiplier;
+        }
+
+        private final AtomicDirectory mHistoricalAppOpsDir = new AtomicDirectory(
+                new File(new File(Environment.getDataSystemDeDirectory(), "appops"), "history"));
+
+        private File generateFile(@NonNull File baseDir, int depth) {
+            final long globalBeginMillis = computeGlobalIntervalBeginMillis(depth);
+            return new File(baseDir, Long.toString(globalBeginMillis) + HISTORY_FILE_SUFFIX);
+        }
+
+        void clearHistoryDLocked() {
+            mHistoricalAppOpsDir.delete();
+        }
+
+        void persistHistoricalOpsDLocked(@NonNull List<HistoricalOps> ops) {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Persisting ops:\n" + opsToDebugString(ops));
+                enforceOpsWellFormed(ops);
+            }
+            try {
+                final File newBaseDir = mHistoricalAppOpsDir.startWrite();
+                final File oldBaseDir = mHistoricalAppOpsDir.getBackupDirectory();
+                handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir, ops, 0);
+                mHistoricalAppOpsDir.finishWrite();
+            } catch (Throwable t) {
+                Slog.wtf(LOG_TAG, "Failed to write historical app ops, restoring backup", t);
+                mHistoricalAppOpsDir.failWrite();
+            }
+        }
+
+        @Nullable List<HistoricalOps> readHistoryRawDLocked() {
+            return collectHistoricalOpsBaseDLocked(Process.INVALID_UID /*filterUid*/,
+                    null /*filterPackageName*/, null /*filterOpNames*/,
+                    0 /*filterBeginTimeMills*/, Long.MAX_VALUE /*filterEndTimeMills*/);
+        }
+
+        @Nullable List<HistoricalOps> readHistoryDLocked() {
+            final List<HistoricalOps> result = readHistoryRawDLocked();
+            // Take into account in memory state duration.
+            if (result != null) {
+                final int opCount = result.size();
+                for (int i = 0; i < opCount; i++) {
+                    result.get(i).offsetBeginAndEndTime(mBaseSnapshotInterval);
+                }
+            }
+            return result;
+        }
+
+        long getLastPersistTimeMillisDLocked() {
+            try {
+                final File baseDir = mHistoricalAppOpsDir.startRead();
+                final File file = generateFile(baseDir, 0);
+                if (file.exists()) {
+                    return file.lastModified();
+                }
+                mHistoricalAppOpsDir.finishRead();
+            } catch (IOException e) {
+                Slog.wtf("Error reading historical app ops. Deleting history.", e);
+                mHistoricalAppOpsDir.delete();
+            }
+            return 0;
+        }
+
+        private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps,
+                int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeingMillis, long filterEndMillis) {
+            final List<HistoricalOps> readOps = collectHistoricalOpsBaseDLocked(filterUid,
+                    filterPackageName, filterOpNames, filterBeingMillis, filterEndMillis);
+            if (readOps != null) {
+                final int readCount = readOps.size();
+                for (int i = 0; i < readCount; i++) {
+                    final HistoricalOps readOp = readOps.get(i);
+                    currentOps.merge(readOp);
+                }
+             }
+        }
+
+        private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(
+                int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeginTimeMillis, long filterEndTimeMillis) {
+            try {
+                final File baseDir = mHistoricalAppOpsDir.startRead();
+                final File[] files = baseDir.listFiles();
+                if (files == null) {
+                    return null;
+                }
+                final ArraySet<File> historyFiles = new ArraySet<>(files.length);
+                for (File file : files) {
+                    if (file.isFile() && file.getName().endsWith(HISTORY_FILE_SUFFIX)) {
+                        historyFiles.add(file);
+                    }
+                }
+                final long[] globalContentOffsetMillis = {0};
+                final LinkedList<HistoricalOps> ops = collectHistoricalOpsRecursiveDLocked(
+                        baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+                        filterEndTimeMillis, globalContentOffsetMillis, null /*outOps*/,
+                        0 /*depth*/, historyFiles);
+                mHistoricalAppOpsDir.finishRead();
+                return ops;
+            } catch (IOException | XmlPullParserException e) {
+                Slog.wtf("Error reading historical app ops. Deleting history.", e);
+                mHistoricalAppOpsDir.delete();
+            }
+            return null;
+        }
+
+        private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsRecursiveDLocked(
+                @NonNull File baseDir, int filterUid, @NonNull String filterPackageName,
+                @Nullable String[] filterOpNames, long filterBeginTimeMillis,
+                long filterEndTimeMillis, @NonNull long[] globalContentOffsetMillis,
+                @Nullable LinkedList<HistoricalOps> outOps, int depth,
+                @NonNull ArraySet<File> historyFiles)
+                throws IOException, XmlPullParserException {
+            final long previousIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth) * mBaseSnapshotInterval;
+            final long currentIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth + 1) * mBaseSnapshotInterval;
+
+            filterBeginTimeMillis = Math.max(filterBeginTimeMillis - previousIntervalEndMillis, 0);
+            filterEndTimeMillis = filterEndTimeMillis - previousIntervalEndMillis;
+
+            // Read historical data at this level
+            final List<HistoricalOps> readOps = readHistoricalOpsLocked(baseDir,
+                    previousIntervalEndMillis, currentIntervalEndMillis, filterUid,
+                    filterPackageName, filterOpNames, filterBeginTimeMillis, filterEndTimeMillis,
+                    globalContentOffsetMillis, depth, historyFiles);
+
+            // Empty is a special signal to stop diving
+            if (readOps != null && readOps.isEmpty()) {
+                return outOps;
+            }
+
+            // Collect older historical data from subsequent levels
+            outOps = collectHistoricalOpsRecursiveDLocked(
+                    baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+                    filterEndTimeMillis, globalContentOffsetMillis, outOps, depth + 1,
+                    historyFiles);
+
+            // Make older historical data relative to the current historical level
+            if (outOps != null) {
+                final int opCount = outOps.size();
+                for (int i = 0; i < opCount; i++) {
+                    final HistoricalOps collectedOp = outOps.get(i);
+                    collectedOp.offsetBeginAndEndTime(currentIntervalEndMillis);
+                }
+            }
+
+            if (readOps != null) {
+                if (outOps == null) {
+                    outOps = new LinkedList<>();
+                }
+                // Add the read ops to output
+                final int opCount = readOps.size();
+                for (int i = opCount - 1; i >= 0; i--) {
+                    outOps.offerFirst(readOps.get(i));
+                }
+            }
+
+            return outOps;
+        }
+
+        private boolean createHardLinkToExistingFile(@NonNull File fromFile, @NonNull File toFile)
+                throws IOException {
+            if (!fromFile.exists()) {
+                return false;
+            }
+            Files.createLink(toFile.toPath(), fromFile.toPath());
+            return true;
+        }
+
+        private void handlePersistHistoricalOpsRecursiveDLocked(@NonNull File newBaseDir,
+                @NonNull File oldBaseDir, @Nullable List<HistoricalOps> passedOps, int depth)
+                throws IOException, XmlPullParserException {
+            final long previousIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth) * mBaseSnapshotInterval;
+            final long currentIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth + 1) * mBaseSnapshotInterval;
+
+            if (passedOps == null || passedOps.isEmpty()) {
+                // If there is an old file we need to copy it over to the new state.
+                final File oldFile = generateFile(oldBaseDir, depth);
+                final File newFile = generateFile(newBaseDir, depth);
+                if (createHardLinkToExistingFile(oldFile, newFile)) {
+                    handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir,
+                            passedOps, depth + 1);
+                }
+                return;
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(passedOps);
+            }
+
+            // Normalize passed ops time to be based off this interval start
+            final int passedOpCount = passedOps.size();
+            for (int i = 0; i < passedOpCount; i++) {
+                final HistoricalOps passedOp = passedOps.get(i);
+                passedOp.offsetBeginAndEndTime(-previousIntervalEndMillis);
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(passedOps);
+            }
+
+            // Read persisted ops for this interval
+            final List<HistoricalOps> existingOps = readHistoricalOpsLocked(oldBaseDir,
+                    previousIntervalEndMillis, currentIntervalEndMillis,
+                    Process.INVALID_UID /*filterUid*/, null /*filterPackageName*/,
+                    null /*filterOpNames*/, Long.MIN_VALUE /*filterBeginTimeMillis*/,
+                    Long.MAX_VALUE /*filterEndTimeMillis*/, null, depth,
+                    null /*historyFiles*/);
+
+            if (DEBUG) {
+                enforceOpsWellFormed(existingOps);
+            }
+
+            // Offset existing ops to account for elapsed time
+            final int existingOpCount = existingOps.size();
+            if (existingOpCount > 0) {
+                // Compute elapsed time
+                final long elapsedTimeMillis = passedOps.get(passedOps.size() - 1)
+                        .getEndTimeMillis();
+                for (int i = 0; i < existingOpCount; i++) {
+                    final HistoricalOps existingOp = existingOps.get(i);
+                    existingOp.offsetBeginAndEndTime(elapsedTimeMillis);
+                }
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(existingOps);
+            }
+
+            final long slotDurationMillis = previousIntervalEndMillis;
+
+            // Consolidate passed ops at the current slot duration ensuring each snapshot is
+            // full. To achieve this we put all passed and existing ops in a list and will
+            // merge them to ensure each represents a snapshot at the current granularity.
+            final List<HistoricalOps> allOps = new LinkedList<>();
+            allOps.addAll(passedOps);
+            allOps.addAll(existingOps);
+
+            if (DEBUG) {
+                enforceOpsWellFormed(allOps);
+            }
+
+            // Compute ops to persist and overflow ops
+            List<HistoricalOps> persistedOps = null;
+            List<HistoricalOps> overflowedOps = null;
+
+            // We move a snapshot into the next level only if the start time is
+            // after the end of the current interval. This avoids rewriting all
+            // files to propagate the information added to the history on every
+            // iteration. Instead, we would rewrite the next level file only if
+            // an entire snapshot from the previous level is being propagated.
+            // The trade off is that we need to store how much the last snapshot
+            // of the current interval overflows past the interval end. We write
+            // the overflow data to avoid parsing all snapshots on query.
+            long intervalOverflowMillis = 0;
+            final int opCount = allOps.size();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOps op = allOps.get(i);
+                final HistoricalOps persistedOp;
+                final HistoricalOps overflowedOp;
+                if (op.getEndTimeMillis() <= currentIntervalEndMillis) {
+                    persistedOp = op;
+                    overflowedOp = null;
+                } else if (op.getBeginTimeMillis() < currentIntervalEndMillis) {
+                    persistedOp = op;
+                    intervalOverflowMillis = op.getEndTimeMillis() - currentIntervalEndMillis;
+                    if (intervalOverflowMillis > previousIntervalEndMillis) {
+                        final double splitScale = (double) intervalOverflowMillis
+                                / op.getDurationMillis();
+                        overflowedOp = spliceFromEnd(op, splitScale);
+                        intervalOverflowMillis = op.getEndTimeMillis() - currentIntervalEndMillis;
+                    } else {
+                        overflowedOp = null;
+                    }
+                } else {
+                    persistedOp = null;
+                    overflowedOp = op;
+                }
+                if (persistedOp != null) {
+                    if (persistedOps == null) {
+                        persistedOps = new ArrayList<>();
+                    }
+                    persistedOps.add(persistedOp);
+                }
+                if (overflowedOp != null) {
+                    if (overflowedOps == null) {
+                        overflowedOps = new ArrayList<>();
+                    }
+                    overflowedOps.add(overflowedOp);
+                }
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(persistedOps);
+                enforceOpsWellFormed(overflowedOps);
+            }
+
+            if (persistedOps != null) {
+                normalizeSnapshotForSlotDuration(persistedOps, slotDurationMillis);
+                final File newFile = generateFile(newBaseDir, depth);
+                writeHistoricalOpsDLocked(persistedOps, intervalOverflowMillis, newFile);
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "Persisted at depth: " + depth
+                            + " ops:\n" + opsToDebugString(persistedOps));
+                    enforceOpsWellFormed(persistedOps);
+                }
+            }
+
+            handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir,
+                    overflowedOps, depth + 1);
+        }
+
+        private @NonNull List<HistoricalOps> readHistoricalOpsLocked(File baseDir,
+                long intervalBeginMillis, long intervalEndMillis, int filterUid,
+                @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeginTimeMillis, long filterEndTimeMillis,
+                @Nullable long[] cumulativeOverflowMillis, int depth,
+                @NonNull ArraySet<File> historyFiles)
+                throws IOException, XmlPullParserException {
+            final File file = generateFile(baseDir, depth);
+            if (historyFiles != null) {
+                historyFiles.remove(file);
+            }
+            if (filterBeginTimeMillis >= filterEndTimeMillis
+                    || filterEndTimeMillis < intervalBeginMillis) {
+                // Don't go deeper
+                return Collections.emptyList();
+            }
+            if (filterBeginTimeMillis >= (intervalEndMillis
+                    + ((intervalEndMillis - intervalBeginMillis) / mIntervalCompressionMultiplier)
+                    + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0))
+                    || !file.exists()) {
+                if (historyFiles == null || historyFiles.isEmpty()) {
+                    // Don't go deeper
+                    return Collections.emptyList();
+                } else {
+                    // Keep diving
+                    return null;
+                }
+            }
+            return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterOpNames,
+                    filterBeginTimeMillis, filterEndTimeMillis, cumulativeOverflowMillis);
+        }
+
+        private @Nullable List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
+                int filterUid, @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeginTimeMillis, long filterEndTimeMillis,
+                @Nullable long[] cumulativeOverflowMillis)
+                throws IOException, XmlPullParserException {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Reading ops from:" + file);
+            }
+            List<HistoricalOps> allOps = null;
+            try (FileInputStream stream = new FileInputStream(file)) {
+                final XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(stream, StandardCharsets.UTF_8.name());
+                XmlUtils.beginDocument(parser, TAG_HISTORY);
+                final long overflowMillis = XmlUtils.readLongAttribute(parser, ATTR_OVERFLOW, 0);
+                final int depth = parser.getDepth();
+                while (XmlUtils.nextElementWithin(parser, depth)) {
+                    if (TAG_OPS.equals(parser.getName())) {
+                        final HistoricalOps ops = readeHistoricalOpsDLocked(parser,
+                                filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+                                filterEndTimeMillis, cumulativeOverflowMillis);
+                        if (ops == null) {
+                            continue;
+                        }
+                        if (ops.isEmpty()) {
+                            XmlUtils.skipCurrentTag(parser);
+                            continue;
+                        }
+                        if (allOps == null) {
+                            allOps = new ArrayList<>();
+                        }
+                        allOps.add(ops);
+                    }
+                }
+                if (cumulativeOverflowMillis != null) {
+                    cumulativeOverflowMillis[0] += overflowMillis;
+                }
+            } catch (FileNotFoundException e) {
+                Slog.i(LOG_TAG, "No history file: " + file.getName());
+                return Collections.emptyList();
+            }
+            if (DEBUG) {
+                if (allOps != null) {
+                    Slog.i(LOG_TAG, "Read from file: " + file + "ops:\n"
+                            + opsToDebugString(allOps));
+                    enforceOpsWellFormed(allOps);
+                }
+            }
+            return allOps;
+        }
+
+        private @Nullable HistoricalOps readeHistoricalOpsDLocked(
+                @NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
+                @Nullable String[] filterOpNames, long filterBeginTimeMillis,
+                long filterEndTimeMillis, @Nullable long[] cumulativeOverflowMillis)
+                throws IOException, XmlPullParserException {
+            final long beginTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_BEGIN_TIME, 0)
+                    + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
+            final long endTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_END_TIME, 0)
+                    + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
+            // Keep reading as subsequent records may start matching
+            if (filterEndTimeMillis < beginTimeMillis) {
+                return null;
+            }
+            // Stop reading as subsequent records will not match
+            if (filterBeginTimeMillis > endTimeMillis) {
+                return new HistoricalOps(0, 0);
+            }
+            final long filteredBeginTimeMillis = Math.max(beginTimeMillis, filterBeginTimeMillis);
+            final long filteredEndTimeMillis = Math.min(endTimeMillis, filterEndTimeMillis);
+            final double filterScale = (double) (filteredEndTimeMillis - filteredBeginTimeMillis)
+                    / (double) (endTimeMillis - beginTimeMillis);
+            HistoricalOps ops = null;
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_UID.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readHistoricalUidOpsDLocked(ops, parser,
+                            filterUid, filterPackageName, filterOpNames, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            if (ops != null) {
+                ops.setBeginAndEndTime(filteredBeginTimeMillis, filteredEndTimeMillis);
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
+                @Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
+                @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                double filterScale) throws IOException, XmlPullParserException {
+            final int uid = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            if (filterUid != Process.INVALID_UID && filterUid != uid) {
+                XmlUtils.skipCurrentTag(parser);
+                return null;
+            }
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_PACKAGE.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops,
+                            uid, parser, filterPackageName, filterOpNames, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
+                @Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
+                @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                double filterScale) throws IOException, XmlPullParserException {
+            final String packageName = XmlUtils.readStringAttribute(parser, ATTR_NAME);
+            if (filterPackageName != null && !filterPackageName.equals(packageName)) {
+                XmlUtils.skipCurrentTag(parser);
+                return null;
+            }
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_OP.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readHistoricalOpDLocked(ops, uid,
+                            packageName, parser, filterOpNames, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
+                int uid, String packageName, @NonNull XmlPullParser parser,
+                @Nullable String[] filterOpNames, double filterScale)
+                throws IOException, XmlPullParserException {
+            final int op = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            if (filterOpNames != null && !ArrayUtils.contains(filterOpNames,
+                    AppOpsManager.opToName(op))) {
+                XmlUtils.skipCurrentTag(parser);
+                return null;
+            }
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_STATE.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readUidStateDLocked(ops, uid,
+                            packageName, op, parser, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readUidStateDLocked(@Nullable HistoricalOps ops,
+                int uid, String packageName, int op, @NonNull XmlPullParser parser,
+                double filterScale) throws IOException {
+            final int uidState = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            long accessCount = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_COUNT, 0);
+            if (accessCount > 0) {
+                if (!Double.isNaN(filterScale)) {
+                    accessCount = (long) HistoricalOps.round(
+                            (double) accessCount * filterScale);
+                }
+                if (ops == null) {
+                    ops = new HistoricalOps(0, 0);
+                }
+                ops.increaseAccessCount(op, uid, packageName, uidState, accessCount);
+            }
+            long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
+            if (rejectCount > 0) {
+                if (!Double.isNaN(filterScale)) {
+                    rejectCount = (long) HistoricalOps.round(
+                            (double) rejectCount * filterScale);
+                }
+                if (ops == null) {
+                    ops = new HistoricalOps(0, 0);
+                }
+                ops.increaseRejectCount(op, uid, packageName, uidState, rejectCount);
+            }
+            long accessDuration =  XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
+            if (accessDuration > 0) {
+                if (!Double.isNaN(filterScale)) {
+                    accessDuration = (long) HistoricalOps.round(
+                            (double) accessDuration * filterScale);
+                }
+                if (ops == null) {
+                    ops = new HistoricalOps(0, 0);
+                }
+                ops.increaseAccessDuration(op, uid, packageName, uidState, accessDuration);
+            }
+            return ops;
+        }
+
+        private void writeHistoricalOpsDLocked(@Nullable List<HistoricalOps> allOps,
+                long intervalOverflowMillis, @NonNull File file) throws IOException {
+            final FileOutputStream output = mHistoricalAppOpsDir.openWrite(file);
+            try {
+                final XmlSerializer serializer = Xml.newSerializer();
+                serializer.setOutput(output, StandardCharsets.UTF_8.name());
+                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
+                        true);
+                serializer.startDocument(null, true);
+                serializer.startTag(null, TAG_HISTORY);
+                serializer.attribute(null, ATTR_VERSION, String.valueOf(CURRENT_VERSION));
+                if (intervalOverflowMillis != 0) {
+                    serializer.attribute(null, ATTR_OVERFLOW,
+                            Long.toString(intervalOverflowMillis));
+                }
+                if (allOps != null) {
+                    final int opsCount = allOps.size();
+                    for (int i = 0; i < opsCount; i++) {
+                        final HistoricalOps ops = allOps.get(i);
+                        writeHistoricalOpDLocked(ops, serializer);
+                    }
+                }
+                serializer.endTag(null, TAG_HISTORY);
+                serializer.endDocument();
+                mHistoricalAppOpsDir.closeWrite(output);
+            } catch (IOException e) {
+                mHistoricalAppOpsDir.failWrite(output);
+                throw e;
+            }
+        }
+
+        private void writeHistoricalOpDLocked(@NonNull HistoricalOps ops,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_OPS);
+            serializer.attribute(null, ATTR_BEGIN_TIME, Long.toString(ops.getBeginTimeMillis()));
+            serializer.attribute(null, ATTR_END_TIME, Long.toString(ops.getEndTimeMillis()));
+            final int uidCount = ops.getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                final HistoricalUidOps uidOp = ops.getUidOpsAt(i);
+                writeHistoricalUidOpsDLocked(uidOp, serializer);
+            }
+            serializer.endTag(null, TAG_OPS);
+        }
+
+        private void writeHistoricalUidOpsDLocked(@NonNull HistoricalUidOps uidOps,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_UID);
+            serializer.attribute(null, ATTR_NAME, Integer.toString(uidOps.getUid()));
+            final int packageCount = uidOps.getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(i);
+                writeHistoricalPackageOpsDLocked(packageOps, serializer);
+            }
+            serializer.endTag(null, TAG_UID);
+        }
+
+        private void writeHistoricalPackageOpsDLocked(@NonNull HistoricalPackageOps packageOps,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_PACKAGE);
+            serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
+            final int opCount = packageOps.getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp op = packageOps.getOpAt(i);
+                writeHistoricalOpDLocked(op, serializer);
+            }
+            serializer.endTag(null, TAG_PACKAGE);
+        }
+
+        private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_OP);
+            serializer.attribute(null, ATTR_NAME, Integer.toString(op.getOpCode()));
+            for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
+                writeUidStateOnLocked(op, uidState, serializer);
+            }
+            serializer.endTag(null, TAG_OP);
+        }
+
+        private void writeUidStateOnLocked(@NonNull HistoricalOp op, @UidState int uidState,
+                @NonNull XmlSerializer serializer) throws IOException {
+            final long accessCount = op.getAccessCount(uidState);
+            final long rejectCount = op.getRejectCount(uidState);
+            final long accessDuration = op.getAccessDuration(uidState);
+            if (accessCount == 0 && rejectCount == 0 && accessDuration == 0) {
+                return;
+            }
+            serializer.startTag(null, TAG_STATE);
+            serializer.attribute(null, ATTR_NAME, Integer.toString(uidState));
+            if (accessCount > 0) {
+                serializer.attribute(null, ATTR_ACCESS_COUNT, Long.toString(accessCount));
+            }
+            if (rejectCount > 0) {
+                serializer.attribute(null, ATTR_REJECT_COUNT, Long.toString(rejectCount));
+            }
+            if (accessDuration > 0) {
+                serializer.attribute(null, ATTR_ACCESS_DURATION, Long.toString(accessDuration));
+            }
+            serializer.endTag(null, TAG_STATE);
+        }
+
+        private static void enforceOpsWellFormed(@NonNull List<HistoricalOps> ops) {
+            if (ops == null) {
+                return;
+            }
+            HistoricalOps previous;
+            HistoricalOps current = null;
+            final int opsCount = ops.size();
+            for (int i = 0; i < opsCount; i++) {
+                previous = current;
+                current = ops.get(i);
+                if (current.isEmpty()) {
+                    throw new IllegalStateException("Empty ops:\n"
+                            + opsToDebugString(ops));
+                }
+                if (current.getEndTimeMillis() < current.getBeginTimeMillis()) {
+                    throw new IllegalStateException("Begin after end:\n"
+                            + opsToDebugString(ops));
+                }
+                if (previous != null) {
+                    if (previous.getEndTimeMillis() > current.getBeginTimeMillis()) {
+                        throw new IllegalStateException("Intersecting ops:\n"
+                                + opsToDebugString(ops));
+                    }
+                    if (previous.getBeginTimeMillis() > current.getBeginTimeMillis()) {
+                        throw new IllegalStateException("Non increasing ops:\n"
+                                + opsToDebugString(ops));
+                    }
+                }
+            }
+        }
+
+        private long computeGlobalIntervalBeginMillis(int depth) {
+            long beginTimeMillis = 0;
+            for (int i = 0; i < depth + 1; i++) {
+                beginTimeMillis += Math.pow(mIntervalCompressionMultiplier, i);
+            }
+            return beginTimeMillis * mBaseSnapshotInterval;
+        }
+
+        private static @NonNull HistoricalOps spliceFromEnd(@NonNull HistoricalOps ops,
+                double spliceRatio) {
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Splicing from end:" + ops + " ratio:" + spliceRatio);
+            }
+            final HistoricalOps splice = ops.spliceFromEnd(spliceRatio);
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Spliced into:" + ops + " and:" + splice);
+            }
+            return splice;
+        }
+
+
+        private static @NonNull HistoricalOps spliceFromBeginning(@NonNull HistoricalOps ops,
+                double spliceRatio) {
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Splicing from beginning:" + ops + " ratio:" + spliceRatio);
+            }
+            final HistoricalOps splice = ops.spliceFromBeginning(spliceRatio);
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Spliced into:" + ops + " and:" + splice);
+            }
+            return splice;
+        }
+
+        private static void normalizeSnapshotForSlotDuration(@NonNull List<HistoricalOps> ops,
+                long slotDurationMillis) {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Normalizing for slot duration: " + slotDurationMillis
+                        + " ops:\n" + opsToDebugString(ops));
+                enforceOpsWellFormed(ops);
+            }
+            long slotBeginTimeMillis;
+            final int opCount = ops.size();
+            for (int processedIdx = opCount - 1; processedIdx >= 0; processedIdx--) {
+                final HistoricalOps processedOp = ops.get(processedIdx);
+                slotBeginTimeMillis = Math.max(processedOp.getEndTimeMillis()
+                        - slotDurationMillis, 0);
+                for (int candidateIdx = processedIdx - 1; candidateIdx >= 0; candidateIdx--) {
+                    final HistoricalOps candidateOp = ops.get(candidateIdx);
+                    final long candidateSlotIntersectionMillis = candidateOp.getEndTimeMillis()
+                            - Math.min(slotBeginTimeMillis, processedOp.getBeginTimeMillis());
+                    if (candidateSlotIntersectionMillis <= 0) {
+                        break;
+                    }
+                    final float candidateSplitRatio = candidateSlotIntersectionMillis
+                            / (float) candidateOp.getDurationMillis();
+                    if (Float.compare(candidateSplitRatio, 1.0f) >= 0) {
+                        ops.remove(candidateIdx);
+                        processedIdx--;
+                        processedOp.merge(candidateOp);
+                    } else {
+                        final HistoricalOps endSplice = spliceFromEnd(candidateOp,
+                                candidateSplitRatio);
+                        if (endSplice != null) {
+                            processedOp.merge(endSplice);
+                        }
+                        if (candidateOp.isEmpty()) {
+                            ops.remove(candidateIdx);
+                            processedIdx--;
+                        }
+                    }
+                }
+            }
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Normalized for slot duration: " + slotDurationMillis
+                        + " ops:\n" + opsToDebugString(ops));
+                enforceOpsWellFormed(ops);
+            }
+        }
+
+        private static @NonNull String opsToDebugString(@NonNull List<HistoricalOps> ops) {
+            StringBuilder builder = new StringBuilder();
+            final int opCount = ops.size();
+            for (int i = 0; i < opCount; i++) {
+                builder.append("  ");
+                builder.append(ops.get(i));
+                if (i < opCount - 1) {
+                    builder.append('\n');
+                }
+            }
+            return builder.toString();
+        }
+    }
+
+    private final class StringDumpVisitor implements AppOpsManager.HistoricalOpsVisitor {
+        private final long mNow = System.currentTimeMillis();
+
+        private final SimpleDateFormat mDateFormatter = new SimpleDateFormat(
+                "yyyy-MM-dd HH:mm:ss.SSS");
+        private final Date mDate = new Date();
+
+        private final @NonNull String mOpsPrefix;
+        private final @NonNull String mUidPrefix;
+        private final @NonNull String mPackagePrefix;
+        private final @NonNull String mEntryPrefix;
+        private final @NonNull String mUidStatePrefix;
+        private final @NonNull PrintWriter mWriter;
+        private final int mFilterUid;
+        private final String mFilterPackage;
+        private final int mFilterOp;
+
+        StringDumpVisitor(@NonNull String prefix, @NonNull PrintWriter writer,
+                int filterUid, String filterPackage, int filterOp) {
+            mOpsPrefix = prefix + "  ";
+            mUidPrefix = mOpsPrefix + "  ";
+            mPackagePrefix = mUidPrefix + "  ";
+            mEntryPrefix = mPackagePrefix + "  ";
+            mUidStatePrefix = mEntryPrefix + "  ";
+            mWriter = writer;
+            mFilterUid = filterUid;
+            mFilterPackage = filterPackage;
+            mFilterOp = filterOp;
+        }
+
+        @Override
+        public void visitHistoricalOps(HistoricalOps ops) {
+            mWriter.println();
+            mWriter.print(mOpsPrefix);
+            mWriter.println("snapshot:");
+            mWriter.print(mUidPrefix);
+            mWriter.print("begin = ");
+            mDate.setTime(ops.getBeginTimeMillis());
+            mWriter.print(mDateFormatter.format(mDate));
+            mWriter.print("  (");
+            TimeUtils.formatDuration(ops.getBeginTimeMillis() - mNow, mWriter);
+            mWriter.println(")");
+            mWriter.print(mUidPrefix);
+            mWriter.print("end = ");
+            mDate.setTime(ops.getEndTimeMillis());
+            mWriter.print(mDateFormatter.format(mDate));
+            mWriter.print("  (");
+            TimeUtils.formatDuration(ops.getEndTimeMillis() - mNow, mWriter);
+            mWriter.println(")");
+        }
+
+        @Override
+        public void visitHistoricalUidOps(HistoricalUidOps ops) {
+            if (mFilterUid != Process.INVALID_UID && mFilterUid != ops.getUid()) {
+                return;
+            }
+            mWriter.println();
+            mWriter.print(mUidPrefix);
+            mWriter.print("Uid ");
+            UserHandle.formatUid(mWriter, ops.getUid());
+            mWriter.println(":");
+        }
+
+        @Override
+        public void visitHistoricalPackageOps(HistoricalPackageOps ops) {
+            if (mFilterPackage != null && !mFilterPackage.equals(ops.getPackageName())) {
+                return;
+            }
+            mWriter.print(mPackagePrefix);
+            mWriter.print("Package ");
+            mWriter.print(ops.getPackageName());
+            mWriter.println(":");
+        }
+
+        @Override
+        public void visitHistoricalOp(HistoricalOp ops) {
+            if (mFilterOp != AppOpsManager.OP_NONE && mFilterOp != ops.getOpCode()) {
+                return;
+            }
+            mWriter.print(mEntryPrefix);
+            mWriter.print(AppOpsManager.opToName(ops.getOpCode()));
+            mWriter.println(":");
+            for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
+                boolean printedUidState = false;
+                final long accessCount = ops.getAccessCount(uidState);
+                if (accessCount > 0) {
+                    if (!printedUidState) {
+                        mWriter.print(mUidStatePrefix);
+                        mWriter.print(AppOpsManager.uidStateToString(uidState));
+                        mWriter.print("[");
+                        printedUidState = true;
+                    }
+                    mWriter.print("access=");
+                    mWriter.print(accessCount);
+                }
+                final long rejectCount = ops.getRejectCount(uidState);
+                if (rejectCount > 0) {
+                    if (!printedUidState) {
+                        mWriter.print(mUidStatePrefix);
+                        mWriter.print(AppOpsManager.uidStateToString(uidState));
+                        mWriter.print("[");
+                        printedUidState = true;
+                    } else {
+                        mWriter.print(",");
+                    }
+                    mWriter.print("reject=");
+                    mWriter.print(rejectCount);
+                }
+                final long accessDuration = ops.getAccessDuration(uidState);
+                if (accessDuration > 0) {
+                    if (!printedUidState) {
+                        mWriter.print(mUidStatePrefix);
+                        mWriter.print(AppOpsManager.uidStateToString(uidState));
+                        printedUidState = true;
+                    } else {
+                        mWriter.print(",");
+                    }
+                    mWriter.print("duration=");
+                    mWriter.print(accessDuration);
+                }
+                if (printedUidState) {
+                    mWriter.println("]");
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 905f826..9d6628c 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -206,7 +206,7 @@
             switch (event) {
             case AudioManager.RECORD_CONFIG_EVENT_STOP:
                 // return failure if an unknown recording session stopped
-                configChanged = (mRecordConfigs.remove(new Integer(session)) != null);
+                configChanged = (mRecordConfigs.remove(new Integer(portId)) != null);
                 if (configChanged) {
                     sEventLogger.log(new RecordingEvent(event, uid, session, source, null));
                 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 36ca4dc..41fedc5 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -132,10 +132,13 @@
                 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED);
         private final Uri FACE_UNLOCK_APP_ENABLED =
                 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_APP_ENABLED);
+        private final Uri FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
+                Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
 
         private final ContentResolver mContentResolver;
         private boolean mFaceEnabledOnKeyguard;
         private boolean mFaceEnabledForApps;
+        private boolean mFaceAlwaysRequireConfirmation;
 
         /**
          * Creates a content observer.
@@ -158,10 +161,15 @@
                     false /* notifyForDescendents */,
                     this /* observer */,
                     UserHandle.USER_CURRENT);
+            mContentResolver.registerContentObserver(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+                    false /* notifyForDescendents */,
+                    this /* observer */,
+                    UserHandle.USER_CURRENT);
 
             // Update the value immediately
             onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED);
             onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED);
+            onChange(true /* selfChange */, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
         }
 
         @Override
@@ -185,6 +193,13 @@
                                 Settings.Secure.FACE_UNLOCK_APP_ENABLED,
                                 1 /* default */,
                                 UserHandle.USER_CURRENT) != 0;
+            } else if (FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION.equals(uri)) {
+                mFaceAlwaysRequireConfirmation =
+                        Settings.Secure.getIntForUser(
+                                mContentResolver,
+                                Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+                                0 /* default */,
+                                UserHandle.USER_CURRENT) != 0;
             }
         }
 
@@ -195,6 +210,10 @@
         boolean getFaceEnabledForApps() {
             return mFaceEnabledForApps;
         }
+
+        boolean getFaceAlwaysRequireConfirmation() {
+            return mFaceAlwaysRequireConfirmation;
+        }
     }
 
     private final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient {
@@ -332,10 +351,7 @@
                     if (!runningTasks.isEmpty()) {
                         final String topPackage = runningTasks.get(0).topActivity.getPackageName();
                         if (mCurrentAuthSession != null
-                                && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)
-                                && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
-                            // We only care about this state, since <Biometric>Service will
-                            // cancel any client that's still in STATE_AUTH_STARTED
+                                && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
                             mStatusBarService.hideBiometricDialog();
                             mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
                             mCurrentAuthSession.mClientReceiver.onError(
@@ -395,7 +411,7 @@
 
                     // Notify SysUI that the biometric has been authenticated. SysUI already knows
                     // the implicit/explicit state and will react accordingly.
-                    mStatusBarService.onBiometricAuthenticated();
+                    mStatusBarService.onBiometricAuthenticated(true);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Remote exception", e);
                 }
@@ -412,17 +428,20 @@
                         return;
                     }
 
-                    mStatusBarService.onBiometricHelp(getContext().getResources().getString(
-                            com.android.internal.R.string.biometric_not_recognized));
-                    if (requireConfirmation) {
+                    mStatusBarService.onBiometricAuthenticated(false);
+
+                    // TODO: This logic will need to be updated if BP is multi-modal
+                    if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
+                        // Pause authentication. onBiometricAuthenticated(false) causes the
+                        // dialog to show a "try again" button for passive modalities.
                         mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
-                        mStatusBarService.showBiometricTryAgain();
                         // Cancel authentication. Skip the token/package check since we are
                         // cancelling from system server. The interface is permission protected so
                         // this is fine.
                         cancelInternal(null /* token */, null /* package */,
                                 false /* fromClient */);
                     }
+
                     mCurrentAuthSession.mClientReceiver.onAuthenticationFailed();
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Remote exception", e);
@@ -442,8 +461,9 @@
                     if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
                         if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
                             mStatusBarService.onBiometricError(message);
-                            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
                             if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+                                    mActivityTaskManager.unregisterTaskStackListener(
+                                            mTaskStackListener);
                                     mCurrentAuthSession.mClientReceiver.onError(error, message);
                                     mCurrentAuthSession.mState = STATE_AUTH_IDLE;
                                     mCurrentAuthSession = null;
@@ -452,9 +472,14 @@
                                 // Send errors after the dialog is dismissed.
                                 mHandler.postDelayed(() -> {
                                     try {
-                                        mCurrentAuthSession.mClientReceiver.onError(error, message);
-                                        mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                                        mCurrentAuthSession = null;
+                                        if (mCurrentAuthSession != null) {
+                                            mActivityTaskManager.unregisterTaskStackListener(
+                                                    mTaskStackListener);
+                                            mCurrentAuthSession.mClientReceiver.onError(error,
+                                                    message);
+                                            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                                            mCurrentAuthSession = null;
+                                        }
                                     } catch (RemoteException e) {
                                         Slog.e(TAG, "Remote exception", e);
                                     }
@@ -518,6 +543,11 @@
 
             @Override
             public void onDialogDismissed(int reason) throws RemoteException {
+                if (mCurrentAuthSession == null) {
+                    Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
+                    return;
+                }
+
                 if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
                     // Positive button is used by passive modalities as a "confirm" button,
                     // do not send to client
@@ -579,8 +609,10 @@
             }
 
             if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) {
-                final boolean mContinuing = mCurrentAuthSession != null
-                        && mCurrentAuthSession.mState == STATE_AUTH_PAUSED;
+                final boolean continuing = mCurrentAuthSession != null &&
+                        (mCurrentAuthSession.mState == STATE_AUTH_PAUSED
+                                || mCurrentAuthSession.mState == STATE_AUTH_PAUSED_CANCELED);
+
                 mCurrentAuthSession = mPendingAuthSession;
                 mPendingAuthSession = null;
 
@@ -602,7 +634,7 @@
                         modality |= pair.getKey();
                     }
 
-                    if (!mContinuing) {
+                    if (!continuing) {
                         mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
                                 mInternalReceiver, modality, requireConfirmation, userId);
                         mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
@@ -706,7 +738,8 @@
 
                 mCurrentModality = modality;
 
-                // Actually start authentication
+                // Start preparing for authentication. Authentication starts when
+                // all modalities requested have invoked onReadyForAuthentication.
                 authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
                         callingUid, callingPid, callingUserId, modality);
             });
@@ -725,6 +758,9 @@
                 IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
                 int callingUid, int callingPid, int callingUserId, int modality) {
             try {
+                boolean requireConfirmation = bundle.getBoolean(
+                        BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
+
                 // Generate random cookies to pass to the services that should prepare to start
                 // authenticating. Store the cookie here and wait for all services to "ack"
                 // with the cookie. Once all cookies are received, we can show the prompt
@@ -748,7 +784,10 @@
                     Slog.w(TAG, "Iris unsupported");
                 }
                 if ((modality & TYPE_FACE) != 0) {
-                    mFaceService.prepareForAuthentication(true /* requireConfirmation */,
+                    // Check if the user has forced confirmation to be required in Settings.
+                    requireConfirmation = requireConfirmation
+                            || mSettingObserver.getFaceAlwaysRequireConfirmation();
+                    mFaceService.prepareForAuthentication(requireConfirmation,
                             token, sessionId, userId, mInternalReceiver, opPackageName,
                             cookie, callingUid, callingPid, callingUserId);
                 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 32219aa..ecc3d2d 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -819,8 +819,6 @@
 
     // Should be done on a handler thread - not on the Binder's thread.
     private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
-        updateActiveGroup(client.getGroupId(), opPackageName);
-
         if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
 
         int lockoutMode = getLockoutMode();
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 72f73f6..5a9c1ac 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -133,10 +133,11 @@
         }
 
         @Override // Binder call
-        public void authenticate(final IBinder token, final long opId,
+        public void authenticate(final IBinder token, final long opId, int userId,
                 final IFaceServiceReceiver receiver, final int flags,
                 final String opPackageName) {
             checkPermission(USE_BIOMETRIC_INTERNAL);
+            updateActiveGroup(userId, opPackageName);
             final boolean restricted = isRestricted();
             final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
@@ -156,7 +157,7 @@
                     mDaemonWrapper, mHalDeviceId, token,
                     new BiometricPromptServiceListenerImpl(wrapperReceiver),
                     mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, cookie,
-                    true /* requireConfirmation */);
+                    requireConfirmation);
             authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
                     callingUserId);
         }
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 3895ef7..1613dc9 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -159,6 +159,7 @@
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName) {
+            updateActiveGroup(groupId, opPackageName);
             final boolean restricted = isRestricted();
             final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
index 24865bc..6fa98b8 100644
--- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
+++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
@@ -21,22 +21,6 @@
  * @hide
  */
 public class ConnectivityConstants {
-    // IPC constants
-    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
-            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
-    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
-    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
-    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
-    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
-    public static final String EXTRA_CELL_ID = "extra_cellid";
-    public static final String EXTRA_SSID = "extra_ssid";
-    public static final String EXTRA_BSSID = "extra_bssid";
-    /** real time since boot */
-    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
-    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
-
-    public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
-            "android.permission.ACCESS_NETWORK_CONDITIONS";
 
     // Penalty applied to scores of Networks that have not been validated.
     public static final int UNVALIDATED_SCORE_PENALTY = 40;
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index b8f057d..d8bb635 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -18,10 +18,9 @@
 
 import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
+import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
 import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
@@ -35,6 +34,7 @@
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.Uri;
+import android.net.shared.PrivateDnsConfig;
 import android.os.Binder;
 import android.os.INetworkManagementService;
 import android.os.UserHandle;
@@ -43,10 +43,7 @@
 import android.util.Pair;
 import android.util.Slog;
 
-import com.android.server.connectivity.MockableSystemProperties;
-
 import java.net.InetAddress;
-import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -54,10 +51,8 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
 import java.util.Set;
-import java.util.StringJoiner;
+import java.util.stream.Collectors;
 
 
 /**
@@ -123,43 +118,6 @@
     private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
     private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
 
-    public static class PrivateDnsConfig {
-        public final boolean useTls;
-        public final String hostname;
-        public final InetAddress[] ips;
-
-        public PrivateDnsConfig() {
-            this(false);
-        }
-
-        public PrivateDnsConfig(boolean useTls) {
-            this.useTls = useTls;
-            this.hostname = "";
-            this.ips = new InetAddress[0];
-        }
-
-        public PrivateDnsConfig(String hostname, InetAddress[] ips) {
-            this.useTls = !TextUtils.isEmpty(hostname);
-            this.hostname = useTls ? hostname : "";
-            this.ips = (ips != null) ? ips : new InetAddress[0];
-        }
-
-        public PrivateDnsConfig(PrivateDnsConfig cfg) {
-            useTls = cfg.useTls;
-            hostname = cfg.hostname;
-            ips = cfg.ips;
-        }
-
-        public boolean inStrictMode() {
-            return useTls && !TextUtils.isEmpty(hostname);
-        }
-
-        public String toString() {
-            return PrivateDnsConfig.class.getSimpleName() +
-                    "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
-        }
-    }
-
     public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
         final String mode = getPrivateDnsMode(cr);
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 262184b..54c89aa 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,9 +16,8 @@
 
 package com.android.server.connectivity;
 
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-
 import android.content.Context;
+import android.net.INetworkMonitor;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -29,7 +28,6 @@
 import android.os.Handler;
 import android.os.INetworkManagementService;
 import android.os.Messenger;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.SparseArray;
@@ -37,11 +35,8 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.WakeupMessage;
 import com.android.server.ConnectivityService;
-import com.android.server.connectivity.NetworkMonitor;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.Objects;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -126,7 +121,6 @@
     public LinkProperties linkProperties;
     // This should only be modified via ConnectivityService.updateCapabilities().
     public NetworkCapabilities networkCapabilities;
-    public final NetworkMonitor networkMonitor;
     public final NetworkMisc networkMisc;
     // Indicates if netd has been told to create this Network. From this point on the appropriate
     // routing rules are setup and routes are added so packets can begin flowing over the Network.
@@ -239,6 +233,9 @@
     // Used by ConnectivityService to keep track of 464xlat.
     public Nat464Xlat clatd;
 
+    // Set after asynchronous creation of the NetworkMonitor.
+    private volatile INetworkMonitor mNetworkMonitor;
+
     private static final String TAG = ConnectivityService.class.getSimpleName();
     private static final boolean VDBG = false;
     private final ConnectivityService mConnService;
@@ -247,7 +244,7 @@
 
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
-            NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
+            NetworkMisc misc, ConnectivityService connService) {
         this.messenger = messenger;
         asyncChannel = ac;
         network = net;
@@ -258,10 +255,16 @@
         mConnService = connService;
         mContext = context;
         mHandler = handler;
-        networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
         networkMisc = misc;
     }
 
+    /**
+     * Inform NetworkAgentInfo that a new NetworkMonitor was created.
+     */
+    public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
+        mNetworkMonitor = networkMonitor;
+    }
+
     public ConnectivityService connService() {
         return mConnService;
     }
@@ -278,6 +281,15 @@
         return network;
     }
 
+    /**
+     * Get the INetworkMonitor in this NetworkAgentInfo.
+     *
+     * <p>This will be null before {@link #onNetworkMonitorCreated(INetworkMonitor)} is called.
+     */
+    public INetworkMonitor networkMonitor() {
+        return mNetworkMonitor;
+    }
+
     // Functions for manipulating the requests satisfied by this network.
     //
     // These functions must only called on ConnectivityService's main thread.
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 73d3d95..b332c47 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -18,7 +18,9 @@
 
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION;
 
+import android.Manifest;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.TypeEvaluator;
@@ -31,6 +33,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.IColorDisplayManager;
@@ -39,6 +42,7 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.provider.Settings.System;
@@ -61,6 +65,7 @@
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeParseException;
+import java.util.Arrays;
 
 /**
  * Controls the display's color transforms.
@@ -83,6 +88,10 @@
         Matrix.setIdentityM(MATRIX_IDENTITY, 0);
     }
 
+    private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 0;
+    private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 1;
+    private static final int MSG_APPLY_GLOBAL_SATURATION = 2;
+
     /**
      * Evaluator used to animate color matrix transitions.
      */
@@ -161,6 +170,53 @@
         }
     };
 
+    private final TintController mGlobalSaturationTintController = new TintController() {
+
+        private float[] mMatrixGlobalSaturation = new float[16];
+
+        @Override
+        public void setUp(Context context, boolean needsLinear) {
+        }
+
+        @Override
+        public float[] getMatrix() {
+            return Arrays.copyOf(mMatrixGlobalSaturation, mMatrixGlobalSaturation.length);
+        }
+
+        @Override
+        public void setMatrix(int saturationLevel) {
+            if (saturationLevel < 0) {
+                saturationLevel = 0;
+            } else if (saturationLevel > 100) {
+                saturationLevel = 100;
+            }
+            Slog.d(TAG, "Setting saturation level: " + saturationLevel);
+
+            if (saturationLevel == 100) {
+                Matrix.setIdentityM(mMatrixGlobalSaturation, 0);
+            } else {
+                float saturation = saturationLevel * 0.1f;
+                float desaturation = 1.0f - saturation;
+                float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
+                    0.072f * desaturation};
+                mMatrixGlobalSaturation[0] = luminance[0] + saturation;
+                mMatrixGlobalSaturation[1] = luminance[0];
+                mMatrixGlobalSaturation[2] = luminance[0];
+                mMatrixGlobalSaturation[4] = luminance[1];
+                mMatrixGlobalSaturation[5] = luminance[1] + saturation;
+                mMatrixGlobalSaturation[6] = luminance[1];
+                mMatrixGlobalSaturation[8] = luminance[2];
+                mMatrixGlobalSaturation[9] = luminance[2];
+                mMatrixGlobalSaturation[10] = luminance[2] + saturation;
+            }
+        }
+
+        @Override
+        public int getLevel() {
+            return LEVEL_COLOR_MATRIX_SATURATION;
+        }
+    };
+
     private final Handler mHandler;
 
     private int mCurrentUser = UserHandle.USER_NULL;
@@ -178,7 +234,7 @@
 
     public ColorDisplayService(Context context) {
         super(context);
-        mHandler = new Handler(Looper.getMainLooper());
+        mHandler = new TintHandler(Looper.getMainLooper());
     }
 
     @Override
@@ -904,6 +960,23 @@
         void onDisplayWhiteBalanceStatusChanged(boolean enabled);
     }
 
+    private final class TintHandler extends Handler {
+
+        TintHandler(Looper looper) {
+            super(looper, null, true /* async */);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_APPLY_GLOBAL_SATURATION:
+                    mGlobalSaturationTintController.setMatrix(msg.arg1);
+                    applyTint(mGlobalSaturationTintController, false);
+                    break;
+            }
+        }
+    }
+
     private final class BinderService extends IColorDisplayManager.Stub {
 
         @Override
@@ -915,5 +988,27 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        public boolean setSaturationLevel(int level) {
+            final boolean hasTransformsPermission = getContext()
+                    .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+                    == PackageManager.PERMISSION_GRANTED;
+            final boolean hasLegacyPermission = getContext()
+                    .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
+                    == PackageManager.PERMISSION_GRANTED;
+            if (!hasTransformsPermission && !hasLegacyPermission) {
+                throw new SecurityException("Permission required to set display saturation level");
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
+                message.arg1 = level;
+                mHandler.sendMessage(message);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return true;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b1ba05c..4a17c65 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -724,27 +724,6 @@
         }
     }
 
-    private void setSaturationLevelInternal(float level) {
-        if (level < 0 || level > 1) {
-            throw new IllegalArgumentException("Saturation level must be between 0 and 1");
-        }
-        float[] matrix = (level == 1.0f ? null : computeSaturationMatrix(level));
-        DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-        dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION, matrix);
-    }
-
-    private static float[] computeSaturationMatrix(float saturation) {
-        float desaturation = 1.0f - saturation;
-        float[] luminance = {0.231f * desaturation, 0.715f * desaturation, 0.072f * desaturation};
-        float[] matrix = {
-            luminance[0] + saturation, luminance[0], luminance[0], 0,
-            luminance[1], luminance[1] + saturation, luminance[1], 0,
-            luminance[2], luminance[2], luminance[2] + saturation, 0,
-            0, 0, 0, 1
-        };
-        return matrix;
-    }
-
     private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
             IMediaProjection projection, int callingUid, String packageName, String name, int width,
             int height, int densityDpi, Surface surface, int flags, String uniqueId) {
@@ -1836,19 +1815,6 @@
         }
 
         @Override // Binder call
-        public void setSaturationLevel(float level) {
-            mContext.enforceCallingOrSelfPermission(
-                   Manifest.permission.CONTROL_DISPLAY_SATURATION,
-                   "Permission required to set display saturation level");
-            final long token = Binder.clearCallingIdentity();
-            try {
-                setSaturationLevelInternal(level);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override // Binder call
         public int createVirtualDisplay(IVirtualDisplayCallback callback,
                 IMediaProjection projection, String packageName, String name,
                 int width, int height, int densityDpi, Surface surface, int flags,
diff --git a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
index ed17de5..18d328d 100644
--- a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
@@ -21,14 +21,15 @@
  * Feature action that handles Audio Return Channel initiated by AVR devices.
  */
 public class ArcInitiationActionFromAvr extends HdmiCecFeatureAction {
-    // TODO(shubang): add tests
-
     // State in which waits for ARC response.
     private static final int STATE_WAITING_FOR_INITIATE_ARC_RESPONSE = 1;
     private static final int STATE_ARC_INITIATED = 2;
 
     // the required maximum response time specified in CEC 9.2
     private static final int TIMEOUT_MS = 1000;
+    private static final int MAX_RETRY_COUNT = 5;
+
+    private int mSendRequestActiveSourceRetryCount = 0;
 
     ArcInitiationActionFromAvr(HdmiCecLocalDevice source) {
         super(source);
@@ -56,7 +57,12 @@
                 return true;
             case Constants.MESSAGE_REPORT_ARC_INITIATED:
                 mState = STATE_ARC_INITIATED;
-                finish();
+                if (audioSystem().getActiveSource().physicalAddress != getSourcePath()
+                        && audioSystem().isSystemAudioActivated()) {
+                    sendRequestActiveSource();
+                } else {
+                    finish();
+                }
                 return true;
         }
         return false;
@@ -91,4 +97,19 @@
         finish();
     }
 
+    protected void sendRequestActiveSource() {
+        sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()),
+                result -> {
+                    if (result != SendMessageResult.SUCCESS) {
+                        if (mSendRequestActiveSourceRetryCount < MAX_RETRY_COUNT) {
+                            mSendRequestActiveSourceRetryCount++;
+                            sendRequestActiveSource();
+                        } else {
+                            finish();
+                        }
+                    } else {
+                        finish();
+                    }
+                });
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
index 7e73321..eb7c0cd 100644
--- a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
@@ -50,6 +50,9 @@
             case Constants.MESSAGE_REPORT_ARC_TERMINATED:
                 mState = STATE_ARC_TERMINATED;
                 audioSystem().setArcStatus(false);
+                if (audioSystem().getLocalActivePort() == Constants.CEC_SWITCH_ARC) {
+                    audioSystem().routeToInputFromPortId(audioSystem().getRoutingPort());
+                }
                 finish();
                 return true;
         }
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index ea01a0b..6f5a196 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -256,6 +256,41 @@
     static final int USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 1;
     static final int NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 2;
 
+    // Port id to record local active port for Routing Control features
+    // They are used to map to corresponding Inputs
+    // Current interface is only implemented for specific device.
+    // Developers can add more port number and map them to corresponding inputs on demand.
+    @IntDef({
+        CEC_SWITCH_HOME,
+        CEC_SWITCH_HDMI1,
+        CEC_SWITCH_HDMI2,
+        CEC_SWITCH_HDMI3,
+        CEC_SWITCH_HDMI4,
+        CEC_SWITCH_HDMI5,
+        CEC_SWITCH_HDMI6,
+        CEC_SWITCH_HDMI7,
+        CEC_SWITCH_HDMI8,
+        CEC_SWITCH_ARC,
+        CEC_SWITCH_BLUETOOTH,
+        CEC_SWITCH_OPTICAL,
+        CEC_SWITCH_AUX
+    })
+    @interface LocalActivePort {}
+    static final int CEC_SWITCH_HOME = 0;
+    static final int CEC_SWITCH_HDMI1 = 1;
+    static final int CEC_SWITCH_HDMI2 = 2;
+    static final int CEC_SWITCH_HDMI3 = 3;
+    static final int CEC_SWITCH_HDMI4 = 4;
+    static final int CEC_SWITCH_HDMI5 = 5;
+    static final int CEC_SWITCH_HDMI6 = 6;
+    static final int CEC_SWITCH_HDMI7 = 7;
+    static final int CEC_SWITCH_HDMI8 = 8;
+    static final int CEC_SWITCH_ARC = 17;
+    static final int CEC_SWITCH_BLUETOOTH = 18;
+    static final int CEC_SWITCH_OPTICAL = 19;
+    static final int CEC_SWITCH_AUX = 20;
+    static final int CEC_SWITCH_PORT_MAX = 21;
+
     static final String PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM =
             "persist.sys.hdmi.addr.audiosystem";
     static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
@@ -274,15 +309,48 @@
     static final String PROPERTY_SET_MENU_LANGUAGE = "ro.hdmi.set_menu_language";
 
     /**
+     * Property to save the ARC port id on system audio device.
+     * <p>When ARC is initiated, this port will be used to turn on ARC.
+     */
+    static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
+            "ro.hdmi.property_sytem_audio_device_arc_port";
+
+    /**
      * Property to disable muting logic in System Audio Control handling. Default is true.
      *
      * <p>True means enabling muting logic.
      * <p>False means never mute device.
      */
-    // TODO(OEM): set to true to disable muting.
     static final String PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE =
             "ro.hdmi.property_system_audio_mode_muting_enable";
 
+    /**
+     * When set to true the HdmiControlService will never request a Logical Address for the
+     * playback device type. Default is false.
+     *
+     * <p> This is useful when HDMI CEC multiple device types is not supported by the cec driver
+     */
+    static final String PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS =
+            "ro.hdmi.property_hdmi_cec_never_claim_playback_logical_address";
+
+    /**
+     * A comma separated list of logical addresses that HdmiControlService
+     * will never assign local CEC devices to.
+     *
+     * <p> This is useful when HDMI CEC hardware module can't assign multiple logical addresses
+     * in the range same range of 0-7 or 8-15.
+     */
+    static final String PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES =
+            "ro.hdmi.property_hdmi_cec_never_assign_logical_addresses";
+
+    /**
+     * Property to indicate if the current device is a cec switch device.
+     *
+     * <p> Default is false.
+     */
+    static final String PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH =
+            "ro.hdmi.property_is_device_hdmi_cec_switch";
+
     // Set to false to allow playback device to go to suspend mode even
     // when it's an active source. True by default.
     static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
@@ -323,13 +391,6 @@
             "persist.sys.hdmi.property_sytem_audio_mode_audio_port";
 
     /**
-     * Property to save the ARC port id on system audio device.
-     * <p>When ARC is initiated, this port will be used to turn on ARC.
-     */
-    static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
-            "persist.sys.hdmi.property_sytem_audio_device_arc_port";
-
-    /**
      * Property to indicate if a CEC audio device should forward volume keys when system audio mode
      * is off.
      *
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index de6cdd4..e777ce8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -22,20 +22,25 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.os.SystemProperties;
 import android.util.Slog;
 import android.util.SparseArray;
+
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
+
+import libcore.util.EmptyArray;
+
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.function.Predicate;
 import java.util.concurrent.ArrayBlockingQueue;
-import libcore.util.EmptyArray;
+import java.util.function.Predicate;
+
 import sun.util.locale.LanguageTag;
 
 /**
@@ -112,10 +117,18 @@
 
     private final NativeWrapper mNativeWrapperImpl;
 
+    /** List of logical addresses that should not be assigned to the current device.
+     *
+     * <p>Parsed from {@link Constants#PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES}
+     */
+    private final List<Integer> mNeverAssignLogicalAddresses;
+
     // Private constructor.  Use HdmiCecController.create().
     private HdmiCecController(HdmiControlService service, NativeWrapper nativeWrapper) {
         mService = service;
         mNativeWrapperImpl = nativeWrapper;
+        mNeverAssignLogicalAddresses = mService.getIntList(SystemProperties.get(
+            Constants.PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES));
     }
 
     /**
@@ -208,7 +221,8 @@
         for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
             int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
             if (curAddress != Constants.ADDR_UNREGISTERED
-                    && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) {
+                    && deviceType == HdmiUtils.getTypeFromAddress(curAddress)
+                    && !mNeverAssignLogicalAddresses.contains(curAddress)) {
                 boolean acked = false;
                 for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) {
                     if (sendPollMessage(curAddress, curAddress, 1)) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index 11faa56..2da698b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -252,6 +252,10 @@
         return (HdmiCecLocalDevicePlayback) mSource;
     }
 
+    protected final HdmiCecLocalDeviceSource source() {
+        return (HdmiCecLocalDeviceSource) mSource;
+    }
+
     protected final HdmiCecLocalDeviceTv tv() {
         return (HdmiCecLocalDeviceTv) mSource;
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 7860122..6e1b018 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -18,19 +18,24 @@
 
 import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.hdmi.Constants.LocalActivePort;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -51,6 +56,11 @@
     // Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior.
     // When it expires, we can assume <User Control Release> is received.
     private static final int FOLLOWER_SAFETY_TIMEOUT = 550;
+    /**
+     * Return value of {@link #getLocalPortFromPhysicalAddress(int)}
+     */
+    private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+    private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
 
     protected final HdmiControlService mService;
     protected final int mDeviceType;
@@ -125,9 +135,6 @@
             return s.toString();
         }
     }
-    // Logical address of the active source.
-    @GuardedBy("mLock")
-    protected final ActiveSource mActiveSource = new ActiveSource();
 
     // Active routing path. Physical address of the active source but not all the time, such as
     // when the new active source does not claim itself to be one. Note that we don't keep
@@ -434,10 +441,14 @@
         return true;
     }
 
+    // Audio System device with no Playback device type
+    // needs to refactor this function if it's also a switch
     protected boolean handleRoutingChange(HdmiCecMessage message) {
         return false;
     }
 
+    // Audio System device with no Playback device type
+    // needs to refactor this function if it's also a switch
     protected boolean handleRoutingInformation(HdmiCecMessage message) {
         return false;
     }
@@ -855,9 +866,7 @@
     }
 
     ActiveSource getActiveSource() {
-        synchronized (mLock) {
-            return mActiveSource;
-        }
+        return mService.getActiveSource();
     }
 
     void setActiveSource(ActiveSource newActive) {
@@ -869,10 +878,7 @@
     }
 
     void setActiveSource(int logicalAddress, int physicalAddress) {
-        synchronized (mLock) {
-            mActiveSource.logicalAddress = logicalAddress;
-            mActiveSource.physicalAddress = physicalAddress;
-        }
+        mService.setActiveSource(logicalAddress, physicalAddress);
         mService.setLastInputForMhl(Constants.INVALID_PORT_ID);
     }
 
@@ -1017,6 +1023,19 @@
         return Constants.ADDR_INVALID;
     }
 
+    @ServiceThreadOnly
+    void invokeCallback(IHdmiControlCallback callback, int result) {
+        assertRunOnServiceThread();
+        if (callback == null) {
+            return;
+        }
+        try {
+            callback.onComplete(result);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Invoking callback failed:" + e);
+        }
+    }
+
     void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) {
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildUserControlPressed(mAddress, targetAddress, cecKeycode));
@@ -1030,7 +1049,71 @@
         pw.println("mAddress: " + mAddress);
         pw.println("mPreferredAddress: " + mPreferredAddress);
         pw.println("mDeviceInfo: " + mDeviceInfo);
-        pw.println("mActiveSource: " + mActiveSource);
+        pw.println("mActiveSource: " + getActiveSource());
         pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath));
     }
+
+    /**
+     * Method to parse target physical address to the port number on the current device.
+     *
+     * <p>This check assumes target address is valid.
+     * @param targetPhysicalAddress is the physical address of the target device
+     * @return
+     * If the target device is under the current device, return the port number of current device
+     * that the target device is connected to.
+     *
+     * <p>If the target device has the same physical address as the current device, return
+     * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+     *
+     * <p>If the target device is not under the current device, return
+     * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+     */
+    protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) {
+        int myPhysicalAddress = mService.getPhysicalAddress();
+        if (myPhysicalAddress == targetPhysicalAddress) {
+            return TARGET_SAME_PHYSICAL_ADDRESS;
+        }
+        int finalMask = 0xF000;
+        int mask;
+        int port = 0;
+        for (mask = 0x0F00; mask > 0x000F;  mask >>= 4) {
+            if ((myPhysicalAddress & mask) == 0)  {
+                port = mask & targetPhysicalAddress;
+                break;
+            } else {
+                finalMask |= mask;
+            }
+        }
+        if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) {
+            while (mask != 0x000F) {
+                mask >>= 4;
+                port >>= 4;
+            }
+            return port;
+        }
+        return TARGET_NOT_UNDER_LOCAL_DEVICE;
+    }
+
+    /** Calculates the physical address for {@code activePortId}.
+     *
+     * <p>This method assumes current device physical address is valid.
+     * <p>If the current device is already the leaf of the whole CEC system
+     * and can't have devices under it, will return its own physical address.
+     *
+     * @param activePortId is the local active port Id
+     * @return the calculated physical address of the port
+     */
+    protected int getActivePathOnSwitchFromActivePortId(@LocalActivePort int activePortId) {
+        int myPhysicalAddress = mService.getPhysicalAddress();
+        int finalMask = activePortId << 8;
+        int mask;
+        for (mask = 0x0F00; mask > 0x000F;  mask >>= 4) {
+            if ((myPhysicalAddress & mask) == 0)  {
+                break;
+            } else {
+                finalMask >>= 4;
+            }
+        }
+        return finalMask | myPhysicalAddress;
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 7358eaa..8cfe47f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -20,23 +20,28 @@
 import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON;
 
 import android.annotation.Nullable;
+import android.content.Intent;
+import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.AudioSystem;
+import android.media.tv.TvContract;
 import android.os.SystemProperties;
-import android.provider.Settings.Global;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.hdmi.Constants.AudioCodec;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
+import java.util.HashMap;
+
 /**
  * Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
  * system.
  */
-public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
+public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
 
     private static final String TAG = "HdmiCecLocalDeviceAudioSystem";
 
@@ -51,25 +56,20 @@
 
     private boolean mTvSystemAudioModeSupport;
 
-    // Whether the auido system will turn TV off when it's powering off
-    private boolean mAutoTvOff;
-    // Whether the auido system will broadcast standby to the system when it's powering off
-    private boolean mAutoDeviceOff;
-
     // Whether ARC is available or not. "true" means that ARC is established between TV and
     // AVR as audio receiver.
     @ServiceThreadOnly private boolean mArcEstablished = false;
 
-    /**
-     * Return value of {@link #getLocalPortFromPhysicalAddress(int)}
-     */
-    private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
-    private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+    // If the current device uses TvInput for ARC. We assume all other inputs also use TvInput
+    // when ARC is using TvInput.
+    private boolean mArcIntentUsed = SystemProperties
+            .get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");
 
-    // Local active port number used for Routing Control.
-    // Default 0 means HOME is the current active path. Temp solution only.
-    // TODO(amyjojo): adding system constants for Atom inputs port and TIF mapping.
-    private int mLocalActivePath = 0;
+    // Keeps the mapping (HDMI port ID to TV input URI) to keep track of the TV inputs ready to
+    // accept input switching request from HDMI devices. Requests for which the corresponding
+    // input ID is not yet registered by TV input framework need to be buffered for delayed
+    // processing.
+    private final HashMap<Integer, String> mTvInputs = new HashMap<>();
 
     protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
@@ -77,12 +77,13 @@
         // TODO(amyjojo) make System Audio Control controllable by users
         /*mSystemAudioControlFeatureEnabled =
         mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
-        // TODO(b/80297700): set read-only property in config instead of setting here
-        SystemProperties.set(Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, "false");
-        mAutoDeviceOff = mService.readBooleanSetting(
-                Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true);
-        mAutoTvOff = mService.readBooleanSetting(
-                Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED, true);
+        // TODO(amyjojo): make the map ro property.
+        mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
+                "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
+        mTvInputs.put(Constants.CEC_SWITCH_HDMI2,
+                "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
+        mTvInputs.put(Constants.CEC_SWITCH_HDMI3,
+                "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
     }
 
     @Override
@@ -97,21 +98,6 @@
                     mSystemAudioActivated ? "true" : "false");
         }
         terminateSystemAudioMode();
-
-        HdmiLogger.debug(TAG + " onStandby, initiatedByCec:" + initiatedByCec
-                + ", mAutoDeviceOff: " + mAutoDeviceOff + ", mAutoTvOff: " + mAutoTvOff);
-        if (!mService.isControlEnabled() || initiatedByCec) {
-            return;
-        }
-        if (mAutoDeviceOff) {
-            mService.sendCecCommand(
-                    HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST));
-        } else if (mAutoTvOff) {
-            mService.sendCecCommand(
-                    HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
-        }
-        return;
-
     }
 
     @Override
@@ -143,43 +129,17 @@
             int systemAudioOnPowerOnProp, boolean lastSystemAudioControlStatus) {
         if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
                 || ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
-                        && lastSystemAudioControlStatus)) {
+                && lastSystemAudioControlStatus)) {
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
         }
     }
 
-    @ServiceThreadOnly
-    protected boolean handleActiveSource(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int logicalAddress = message.getSource();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
-        if (!mActiveSource.equals(activeSource)) {
-            setActiveSource(activeSource);
-        }
-        return true;
-    }
-
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleSetStreamPath(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        // If current device is the target path, playback device should handle it.
-        // If the path is under the current device, should switch
-        int port = getLocalPortFromPhysicalAddress(physicalAddress);
-        if (port > 0) {
-            routeToPort(port);
-        }
-        return true;
-    }
-
     @Override
     @ServiceThreadOnly
     protected int getPreferredAddress() {
         assertRunOnServiceThread();
         return SystemProperties.getInt(
-                Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, Constants.ADDR_UNREGISTERED);
+            Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, Constants.ADDR_UNREGISTERED);
     }
 
     @Override
@@ -249,6 +209,7 @@
     @ServiceThreadOnly
     protected boolean handleRequestArcInitiate(HdmiCecMessage message) {
         assertRunOnServiceThread();
+        removeAction(ArcInitiationActionFromAvr.class);
         if (!SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
         } else if (!isDirectConnectToTv()) {
@@ -270,6 +231,7 @@
             HdmiLogger.debug("ARC is not established between TV and AVR device");
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
         } else {
+            removeAction(ArcTerminationActionFromAvr.class);
             addAndStartAction(new ArcTerminationActionFromAvr(this));
         }
         return true;
@@ -323,7 +285,7 @@
         for (int i = 0; i < params.length; i++) {
             byte val = params[i];
             audioFormatCodes[i] =
-                    val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE;
+                val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE;
         }
         return audioFormatCodes;
     }
@@ -333,7 +295,23 @@
     protected boolean handleSystemAudioModeRequest(HdmiCecMessage message) {
         assertRunOnServiceThread();
         boolean systemAudioStatusOn = message.getParams().length != 0;
-        if (!setSystemAudioMode(systemAudioStatusOn)) {
+        // Check if the request comes from a non-TV device.
+        // Need to check if TV supports System Audio Control
+        // if non-TV device tries to turn on the feature
+        if (message.getSource() != Constants.ADDR_TV) {
+            if (systemAudioStatusOn) {
+                handleSystemAudioModeOnFromNonTvDevice(message);
+                return true;
+            }
+        } else {
+            // If TV request the feature on
+            // cache TV supporting System Audio Control
+            // until Audio System loses its physical address.
+            setTvSystemAudioModeSupport(true);
+        }
+        // If TV or Audio System does not support the feature,
+        // will send abort command.
+        if (!checkSupportAndSetSystemAudioMode(systemAudioStatusOn)) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
             return true;
         }
@@ -348,7 +326,8 @@
     @ServiceThreadOnly
     protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
+        if (!checkSupportAndSetSystemAudioMode(
+                HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
         }
         return true;
@@ -358,7 +337,8 @@
     @ServiceThreadOnly
     protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
+        if (!checkSupportAndSetSystemAudioMode(
+                HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
         }
         return true;
@@ -390,7 +370,7 @@
     private void notifyArcStatusToAudioService(boolean enabled) {
         // Note that we don't set any name to ARC.
         mService.getAudioManager()
-                .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
+            .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
     }
 
     private void reportAudioStatus(HdmiCecMessage message) {
@@ -406,7 +386,16 @@
                         mAddress, message.getSource(), scaledVolume, mute));
     }
 
-    protected boolean setSystemAudioMode(boolean newSystemAudioMode) {
+    /**
+     * Method to check if device support System Audio Control. If so, wake up device if necessary.
+     *
+     * <p> then call {@link #setSystemAudioMode(boolean)} to turn on or off System Audio Mode
+     * @param newSystemAudioMode turning feature on or off. True is on. False is off.
+     * @return true or false.
+     *
+     * <p>False when device does not support the feature. Otherwise returns true.
+     */
+    protected boolean checkSupportAndSetSystemAudioMode(boolean newSystemAudioMode) {
         if (!isSystemAudioControlFeatureEnabled()) {
             HdmiLogger.debug(
                     "Cannot turn "
@@ -422,6 +411,17 @@
         if (newSystemAudioMode && mService.isPowerStandbyOrTransient()) {
             mService.wakeUp();
         }
+        setSystemAudioMode(newSystemAudioMode);
+        return true;
+    }
+
+    /**
+     * Real work to turn on or off System Audio Mode.
+     *
+     * Use {@link #checkSupportAndSetSystemAudioMode(boolean)}
+     * if trying to turn on or off the feature.
+     */
+    private void setSystemAudioMode(boolean newSystemAudioMode) {
         int targetPhysicalAddress = getActiveSource().physicalAddress;
         int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress);
         if (newSystemAudioMode && port >= 0) {
@@ -449,48 +449,19 @@
                 mService.announceSystemAudioModeChange(newSystemAudioMode);
             }
         }
-        return true;
-    }
-
-    /**
-     * Method to parse target physical address to the port number on the current device.
-     *
-     * <p>This check assumes target address is valid.
-     * @param targetPhysicalAddress is the physical address of the target device
-     * @return
-     * <p>If the target device is under the current device, return the port number of current device
-     * that the target device is connected to.
-     *
-     * <p>If the target device has the same physical address as the current device, return
-     * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
-     *
-     * <p>If the target device is not under the current device, return
-     * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
-     */
-    protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) {
-        int myPhysicalAddress = mService.getPhysicalAddress();
-        if (myPhysicalAddress == targetPhysicalAddress) {
-            return TARGET_SAME_PHYSICAL_ADDRESS;
-        }
-        int finalMask = 0xF000;
-        int mask;
-        int port = 0;
-        for (mask = 0x0F00; mask > 0x000F;  mask >>= 4) {
-            if ((myPhysicalAddress & mask) == 0)  {
-                port = mask & targetPhysicalAddress;
-                break;
-            } else {
-                finalMask |= mask;
+        // Init arc whenever System Audio Mode is on
+        // Terminate arc when System Audio Mode is off
+        // Since some TVs don't request ARC on with System Audio Mode on request
+        if (SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)
+                && isDirectConnectToTv()) {
+            if (newSystemAudioMode && !isArcEnabled()) {
+                removeAction(ArcInitiationActionFromAvr.class);
+                addAndStartAction(new ArcInitiationActionFromAvr(this));
+            } else if (!newSystemAudioMode && isArcEnabled()) {
+                removeAction(ArcTerminationActionFromAvr.class);
+                addAndStartAction(new ArcTerminationActionFromAvr(this));
             }
         }
-        if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) {
-            while (mask != 0x000F) {
-                mask >>= 4;
-                port >>= 4;
-            }
-            return port;
-        }
-        return TARGET_NOT_UNDER_LOCAL_DEVICE;
     }
 
     protected void switchToAudioInput() {
@@ -515,6 +486,33 @@
         }
     }
 
+    @ServiceThreadOnly
+    void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        // TODO: validate port ID
+        if (portId == getLocalActivePort()) {
+            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+            return;
+        }
+        getActiveSource().invalidate();
+        if (!mService.isControlEnabled()) {
+            setLocalActivePort(portId);
+            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
+            return;
+        }
+        int oldPath = getLocalActivePort() != Constants.CEC_SWITCH_HOME
+                ? getActivePathOnSwitchFromActivePortId(getLocalActivePort())
+                : getDeviceInfo().getPhysicalAddress();
+        int newPath = getActivePathOnSwitchFromActivePortId(portId);
+        if (oldPath == newPath) {
+            return;
+        }
+        setLocalActivePort(portId);
+        HdmiCecMessage routingChange =
+                HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
+        mService.sendCecCommand(routingChange);
+    }
+
     boolean isSystemAudioControlFeatureEnabled() {
         synchronized (mLock) {
             return mSystemAudioControlFeatureEnabled;
@@ -534,7 +532,7 @@
             return;
         }
 
-        if (setSystemAudioMode(false)) {
+        if (checkSupportAndSetSystemAudioMode(false)) {
             // send <Set System Audio Mode> [“Off”]
             mService.sendCecCommand(
                     HdmiCecMessageBuilder.buildSetSystemAudioMode(
@@ -557,6 +555,7 @@
      * <p>The result of the query may be cached until Audio device type is put in standby or loses
      * its physical address.
      */
+    // TODO(amyjojo): making mTvSystemAudioModeSupport null originally and fix the logic.
     void queryTvSystemAudioModeSupport(TvSystemAudioModeSupportedCallback callback) {
         if (!mTvSystemAudioModeSupport) {
             addAndStartAction(new DetectTvSystemAudioModeSupportAction(this, callback));
@@ -565,6 +564,37 @@
         }
     }
 
+    /**
+     * Handler of System Audio Mode Request on from non TV device
+     */
+    void handleSystemAudioModeOnFromNonTvDevice(HdmiCecMessage message) {
+        if (!isSystemAudioControlFeatureEnabled()) {
+            HdmiLogger.debug(
+                    "Cannot turn on" + "system audio mode "
+                            + "because the System Audio Control feature is disabled.");
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+            return;
+        }
+        // Wake up device if it is still on standby
+        if (mService.isPowerStandbyOrTransient()) {
+            mService.wakeUp();
+        }
+        // Check if TV supports System Audio Control.
+        // Handle broadcasting setSystemAudioMode on or aborting message on callback.
+        queryTvSystemAudioModeSupport(new TvSystemAudioModeSupportedCallback() {
+            public void onResult(boolean supported) {
+                if (supported) {
+                    setSystemAudioMode(true);
+                    mService.sendCecCommand(
+                            HdmiCecMessageBuilder.buildSetSystemAudioMode(
+                                    mAddress, Constants.ADDR_BROADCAST, true));
+                } else {
+                    mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+                }
+            }
+        });
+    }
+
     void setTvSystemAudioModeSupport(boolean supported) {
         mTvSystemAudioModeSupport = supported;
     }
@@ -576,26 +606,123 @@
         }
     }
 
-    @ServiceThreadOnly
-    protected void setAutoTvOff(boolean autoTvOff) {
-        assertRunOnServiceThread();
-        mAutoTvOff = autoTvOff;
+    @Override
+    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
+        int port = getLocalPortFromPhysicalAddress(physicalAddress);
+        if (isSystemAudioActivated() && port < 0) {
+            // If system audio mode is on and the new active source is not under the current device,
+            // Will switch to ARC input.
+            // TODO(b/115637145): handle system aduio without ARC
+            routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
+        } else if (mIsSwitchDevice && port >= 0) {
+            // If current device is a switch and the new active source is under it,
+            // will switch to the corresponding active path.
+            routeToInputFromPortId(port);
+        }
+    }
+
+    protected void routeToInputFromPortId(int portId) {
+        if (mArcIntentUsed) {
+            routeToTvInputFromPortId(portId);
+        } else {
+            // TODO(): implement input switching for devices not using TvInput.
+        }
+    }
+
+    protected void routeToTvInputFromPortId(int portId) {
+        if (portId < 0 || portId >= Constants.CEC_SWITCH_PORT_MAX) {
+            HdmiLogger.debug("Invalid port number for Tv Input switching.");
+            return;
+        }
+        // Wake up if the current device if ready to route.
+        if (mService.isPowerStandbyOrTransient()) {
+            mService.wakeUp();
+        }
+        if (portId == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
+            switchToHomeTvInput();
+        } else if (portId == Constants.CEC_SWITCH_ARC) {
+            switchToTvInput(SystemProperties.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT));
+            setLocalActivePort(portId);
+            return;
+        } else {
+            String uri = mTvInputs.get(portId);
+            if (uri != null) {
+                switchToTvInput(mTvInputs.get(portId));
+            } else {
+                HdmiLogger.debug("Port number does not match any Tv Input.");
+                return;
+            }
+        }
+
+        setLocalActivePort(portId);
+        setRoutingPort(portId);
+    }
+
+    // For device to switch to specific TvInput with corresponding URI.
+    private void switchToTvInput(String uri) {
+        mService.getContext().startActivity(new Intent(Intent.ACTION_VIEW,
+                TvContract.buildChannelUriForPassthroughInput(uri))
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+    }
+
+    // For device using TvInput to switch to Home.
+    private void switchToHomeTvInput() {
+        Intent activityIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+                        | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                        | Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_NO_ANIMATION);
+        mService.getContext().startActivity(activityIntent);
     }
 
     @Override
-    @ServiceThreadOnly
-    void setAutoDeviceOff(boolean autoDeviceOff) {
-        assertRunOnServiceThread();
-        mAutoDeviceOff = autoDeviceOff;
+    protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
+        int port = getLocalPortFromPhysicalAddress(physicalAddress);
+        // Routing change or information sent from switches under the current device can be ignored.
+        if (port > 0) {
+            return;
+        }
+        // When other switches route to some other devices not under the current device,
+        // check system audio mode status and do ARC switch if needed.
+        if (port < 0 && isSystemAudioActivated()) {
+            handleRoutingChangeAndInformationForSystemAudio();
+            return;
+        }
+        // When other switches route to the current device
+        // and the current device is also a switch.
+        if (port == 0) {
+            handleRoutingChangeAndInformationForSwitch(message);
+        }
     }
 
-    private void routeToPort(int portId) {
-        // TODO(AMYJOJO): route to specific input of the port
-        mLocalActivePath = portId;
+    // Handle the system audio(ARC) part of the logic on receiving routing change or information.
+    private void handleRoutingChangeAndInformationForSystemAudio() {
+        // TODO(b/115637145): handle system aduio without ARC
+        routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
     }
 
-    @VisibleForTesting
-    protected int getLocalActivePath() {
-        return mLocalActivePath;
+    // Handle the routing control part of the logic on receiving routing change or information.
+    private void handleRoutingChangeAndInformationForSwitch(HdmiCecMessage message) {
+        if (getRoutingPort() == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
+            routeToInputFromPortId(Constants.CEC_SWITCH_HOME);
+            mService.setAndBroadcastActiveSourceFromOneDeviceType(
+                    message.getSource(), mService.getPhysicalAddress());
+            return;
+        }
+
+        int routingInformationPath =
+                getActivePathOnSwitchFromActivePortId(getRoutingPort());
+        // If current device is already the leaf of the whole HDMI system, will do nothing.
+        if (routingInformationPath == mService.getPhysicalAddress()) {
+            HdmiLogger.debug("Current device can't assign valid physical address"
+                    + "to devices under it any more. "
+                    + "It's physical address is " + routingInformationPath);
+            return;
+        }
+        // Otherwise will switch to the current active port and broadcast routing information.
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingInformation(
+                mAddress, routingInformationPath));
+        routeToInputFromPortId(getRoutingPort());
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d45b00b..07db971 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -21,11 +21,11 @@
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
-import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.Settings.Global;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.LocalePicker;
 import com.android.internal.app.LocalePicker.LocaleInfo;
 import com.android.internal.util.IndentingPrintWriter;
@@ -35,12 +35,10 @@
 import java.util.List;
 import java.util.Locale;
 
-import java.util.List;
-
 /**
  * Represent a logical device of type Playback residing in Android system.
  */
-final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
+public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
     private static final String TAG = "HdmiCecLocalDevicePlayback";
 
     private static final boolean WAKE_ON_HOTPLUG =
@@ -49,8 +47,6 @@
     private static final boolean SET_MENU_LANGUAGE =
             SystemProperties.getBoolean(Constants.PROPERTY_SET_MENU_LANGUAGE, false);
 
-    private boolean mIsActiveSource = false;
-
     // Used to keep the device awake while it is the active source. For devices that
     // cannot wake up via CEC commands, this address the inconvenience of having to
     // turn them on. True by default, and can be disabled (i.e. device can go to sleep
@@ -62,6 +58,11 @@
     // If true, turn off TV upon standby. False by default.
     private boolean mAutoTvOff;
 
+    // Local active port number used for Routing Control.
+    // Default 0 means HOME is the current active path. Temp solution only.
+    // TODO(amyjojo): adding system constants for input ports to TIF mapping.
+    private int mLocalActivePath = 0;
+
     HdmiCecLocalDevicePlayback(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
 
@@ -100,25 +101,6 @@
     }
 
     @ServiceThreadOnly
-    void oneTouchPlay(IHdmiControlCallback callback) {
-        assertRunOnServiceThread();
-        List<OneTouchPlayAction> actions = getActions(OneTouchPlayAction.class);
-        if (!actions.isEmpty()) {
-            Slog.i(TAG, "oneTouchPlay already in progress");
-            actions.get(0).addCallback(callback);
-            return;
-        }
-        OneTouchPlayAction action = OneTouchPlayAction.create(this, Constants.ADDR_TV,
-                callback);
-        if (action == null) {
-            Slog.w(TAG, "Cannot initiate oneTouchPlay");
-            invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
-            return;
-        }
-        addAndStartAction(action);
-    }
-
-    @ServiceThreadOnly
     void queryDisplayStatus(IHdmiControlCallback callback) {
         assertRunOnServiceThread();
         List<DevicePowerStatusAction> actions = getActions(DevicePowerStatusAction.class);
@@ -137,16 +119,6 @@
         addAndStartAction(action);
     }
 
-    @ServiceThreadOnly
-    private void invokeCallback(IHdmiControlCallback callback, int result) {
-        assertRunOnServiceThread();
-        try {
-            callback.onComplete(result);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Invoking callback failed:" + e);
-        }
-    }
-
     @Override
     @ServiceThreadOnly
     void onHotplug(int portId, boolean connected) {
@@ -189,7 +161,8 @@
     }
 
     @ServiceThreadOnly
-    void setActiveSource(boolean on) {
+    @VisibleForTesting
+    void setIsActiveSource(boolean on) {
         assertRunOnServiceThread();
         mIsActiveSource = on;
         if (on) {
@@ -227,21 +200,6 @@
         return !getWakeLock().isHeld();
     }
 
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleActiveSource(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        mayResetActiveSource(physicalAddress);
-        return true;  // Broadcast message.
-    }
-
-    private void mayResetActiveSource(int physicalAddress) {
-        if (physicalAddress != mService.getPhysicalAddress()) {
-            setActiveSource(false);
-        }
-    }
-
     @ServiceThreadOnly
     protected boolean handleUserControlPressed(HdmiCecMessage message) {
         assertRunOnServiceThread();
@@ -250,42 +208,7 @@
     }
 
     @Override
-    @ServiceThreadOnly
-    protected boolean handleSetStreamPath(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        maySetActiveSource(physicalAddress);
-        maySendActiveSource(message.getSource());
-        wakeUpIfActiveSource();
-        return true;  // Broadcast message.
-    }
-
-    // Samsung model we tested sends <Routing Change> and <Request Active Source>
-    // in a row, and then changes the input to the internal source if there is no
-    // <Active Source> in response. To handle this, we'll set ActiveSource aggressively.
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleRoutingChange(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
-        maySetActiveSource(newPath);
-        return true;  // Broadcast message.
-    }
-
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleRoutingInformation(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        maySetActiveSource(physicalAddress);
-        return true;  // Broadcast message.
-    }
-
-    private void maySetActiveSource(int physicalAddress) {
-        setActiveSource(physicalAddress == mService.getPhysicalAddress());
-    }
-
-    private void wakeUpIfActiveSource() {
+    protected void wakeUpIfActiveSource() {
         if (!mIsActiveSource) {
             return;
         }
@@ -296,7 +219,8 @@
         }
     }
 
-    private void maySendActiveSource(int dest) {
+    @Override
+    protected void maySendActiveSource(int dest) {
         if (mIsActiveSource) {
             mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
                     mAddress, mService.getPhysicalAddress()));
@@ -306,14 +230,6 @@
         }
     }
 
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        maySendActiveSource(message.getSource());
-        return true;  // Broadcast message.
-    }
-
     @ServiceThreadOnly
     protected boolean handleSetMenuLanguage(HdmiCecMessage message) {
         assertRunOnServiceThread();
@@ -361,16 +277,6 @@
 
     @Override
     @ServiceThreadOnly
-    protected void sendStandby(int deviceId) {
-        assertRunOnServiceThread();
-
-        // Playback device can send <Standby> to TV only. Ignore the parameter.
-        int targetAddress = Constants.ADDR_TV;
-        mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, targetAddress));
-    }
-
-    @Override
-    @ServiceThreadOnly
     protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
         super.disableDevice(initiatedByCec, callback);
 
@@ -379,10 +285,20 @@
             mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
                     mAddress, mService.getPhysicalAddress()));
         }
-        setActiveSource(false);
+        setIsActiveSource(false);
         checkIfPendingActionsCleared();
     }
 
+    private void routeToPort(int portId) {
+        // TODO(AMYJOJO): route to specific input of the port
+        mLocalActivePath = portId;
+    }
+
+    @VisibleForTesting
+    protected int getLocalActivePath() {
+        return mLocalActivePath;
+    }
+
     @Override
     protected void dump(final IndentingPrintWriter pw) {
         super.dump(pw);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
new file mode 100644
index 0000000..6532e16
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -0,0 +1,276 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.hdmi.Constants.LocalActivePort;
+import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+
+import java.util.List;
+
+/**
+ * Represent a logical source device residing in Android system.
+ */
+abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
+
+    private static final String TAG = "HdmiCecLocalDeviceSource";
+
+    // Indicate if current device is Active Source or not
+    @VisibleForTesting
+    protected boolean mIsActiveSource = false;
+
+    // Device has cec switch functionality or not.
+    // Default is false.
+    protected boolean mIsSwitchDevice = SystemProperties.getBoolean(
+            Constants.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+
+    // Routing port number used for Routing Control.
+    // This records the default routing port or the previous valid routing port.
+    // Default is HOME input.
+    // Note that we don't save active path here because for source device,
+    // new Active Source physical address might not match the active path
+    @GuardedBy("mLock")
+    @LocalActivePort
+    private int mRoutingPort = Constants.CEC_SWITCH_HOME;
+
+    // This records the current input of the device.
+    // When device is switched to ARC input, mRoutingPort does not record it
+    // since it's not an HDMI port used for Routing Control.
+    // mLocalActivePort will record whichever input we switch to to keep tracking on
+    // the current input status of the device.
+    // This can help prevent duplicate switching and provide status information.
+    @GuardedBy("mLock")
+    @LocalActivePort
+    protected int mLocalActivePort = Constants.CEC_SWITCH_HOME;
+
+    protected HdmiCecLocalDeviceSource(HdmiControlService service, int deviceType) {
+        super(service, deviceType);
+    }
+
+    @Override
+    @ServiceThreadOnly
+    void onHotplug(int portId, boolean connected) {
+        assertRunOnServiceThread();
+        mCecMessageCache.flushAll();
+        // We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
+        if (mService.isPowerStandbyOrTransient()) {
+            mService.wakeUp();
+        }
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected void sendStandby(int deviceId) {
+        assertRunOnServiceThread();
+
+        // Send standby to TV only for now
+        int targetAddress = Constants.ADDR_TV;
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, targetAddress));
+    }
+
+    @ServiceThreadOnly
+    void oneTouchPlay(IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        List<OneTouchPlayAction> actions = getActions(OneTouchPlayAction.class);
+        if (!actions.isEmpty()) {
+            Slog.i(TAG, "oneTouchPlay already in progress");
+            actions.get(0).addCallback(callback);
+            return;
+        }
+        OneTouchPlayAction action = OneTouchPlayAction.create(this, Constants.ADDR_TV,
+                callback);
+        if (action == null) {
+            Slog.w(TAG, "Cannot initiate oneTouchPlay");
+            invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
+            return;
+        }
+        addAndStartAction(action);
+    }
+
+    @ServiceThreadOnly
+    protected boolean handleActiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int logicalAddress = message.getSource();
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
+        if (!getActiveSource().equals(activeSource)) {
+            setActiveSource(activeSource);
+        }
+        setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
+        switchInputOnReceivingNewActivePath(physicalAddress);
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        maySendActiveSource(message.getSource());
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleSetStreamPath(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        // If current device is the target path, set to Active Source.
+        // If the path is under the current device, should switch
+        if (physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) {
+            setAndBroadcastActiveSource(message, physicalAddress);
+        }
+        switchInputOnReceivingNewActivePath(physicalAddress);
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRoutingChange(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
+        // if the current device is a pure playback device
+        if (!mIsSwitchDevice
+                && newPath == mService.getPhysicalAddress()
+                && mService.isPlaybackDevice()) {
+            setAndBroadcastActiveSource(message, newPath);
+        }
+        handleRoutingChangeAndInformation(newPath, message);
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRoutingInformation(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        // if the current device is a pure playback device
+        if (!mIsSwitchDevice
+                && physicalAddress == mService.getPhysicalAddress()
+                && mService.isPlaybackDevice()) {
+            setAndBroadcastActiveSource(message, physicalAddress);
+        }
+        handleRoutingChangeAndInformation(physicalAddress, message);
+        return true;
+    }
+
+    // Method to switch Input with the new Active Path.
+    // All the devices with Switch functionality should implement this.
+    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
+        // do nothing
+    }
+
+    // Source device with Switch functionality should implement this method.
+    // TODO(): decide which type will handle the routing when multi device type is supported
+    protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
+        // do nothing
+    }
+
+    // Active source claiming needs to be handled in Service
+    // since service can decide who will be the active source when the device supports
+    // multiple device types in this method.
+    // This method should only be called when the device can be the active source.
+    protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
+        mService.setAndBroadcastActiveSource(
+                message, physicalAddress, getDeviceInfo().getDeviceType());
+    }
+
+    @ServiceThreadOnly
+    void setIsActiveSource(boolean on) {
+        assertRunOnServiceThread();
+        mIsActiveSource = on;
+    }
+
+    protected void wakeUpIfActiveSource() {
+        if (!mIsActiveSource) {
+            return;
+        }
+        // Wake up the device if the power is in standby mode
+        if (mService.isPowerStandbyOrTransient()) {
+            mService.wakeUp();
+        }
+        return;
+    }
+
+    protected void maySendActiveSource(int dest) {
+        if (mIsActiveSource) {
+            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
+                    mAddress, mService.getPhysicalAddress()));
+        }
+    }
+
+    /**
+     * Set {@link #mRoutingPort} to a specific {@link LocalActivePort} to record the current active
+     * CEC Routing Control related port.
+     *
+     * @param portId The portId of the new routing port.
+     */
+    @VisibleForTesting
+    protected void setRoutingPort(@LocalActivePort int portId) {
+        synchronized (mLock) {
+            mRoutingPort = portId;
+        }
+    }
+
+    /**
+     * Get {@link #mRoutingPort}. This is useful when the device needs to route to the last valid
+     * routing port.
+     */
+    @LocalActivePort
+    protected int getRoutingPort() {
+        synchronized (mLock) {
+            return mRoutingPort;
+        }
+    }
+
+    /**
+     * Get {@link #mLocalActivePort}. This is useful when device needs to know the current active
+     * port.
+     */
+    @LocalActivePort
+    protected int getLocalActivePort() {
+        synchronized (mLock) {
+            return mLocalActivePort;
+        }
+    }
+
+    /**
+     * Set {@link #mLocalActivePort} to a specific {@link LocalActivePort} to record the current
+     * active port.
+     *
+     * <p>It does not have to be a Routing Control related port. For example it can be
+     * set to {@link Constants#CEC_SWITCH_ARC} but this port is System Audio related.
+     *
+     * @param activePort The portId of the new active port.
+     */
+    protected void setLocalActivePort(@LocalActivePort int activePort) {
+        synchronized (mLock) {
+            mLocalActivePort = activePort;
+        }
+    }
+
+    // Check if the device is trying to switch to the same input that is active right now.
+    // This can help avoid redundant port switching.
+    protected boolean isSwitchingToTheSameInput(@LocalActivePort int activePort) {
+        return activePort == getLocalActivePort();
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 25ca278..b91d8c6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -41,17 +41,18 @@
 import android.media.AudioSystem;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager.TvInputCallback;
-import android.os.RemoteException;
 import android.provider.Settings.Global;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -307,7 +308,7 @@
     private void handleSelectInternalSource() {
         assertRunOnServiceThread();
         // Seq #18
-        if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) {
+        if (mService.isControlEnabled() && getActiveSource().logicalAddress != mAddress) {
             updateActiveSource(mAddress, mService.getPhysicalAddress());
             if (mSkipRoutingControl) {
                 mSkipRoutingControl = false;
@@ -329,7 +330,7 @@
     void updateActiveSource(ActiveSource newActive) {
         assertRunOnServiceThread();
         // Seq #14
-        if (mActiveSource.equals(newActive)) {
+        if (getActiveSource().equals(newActive)) {
             return;
         }
         setActiveSource(newActive);
@@ -402,7 +403,7 @@
             invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
             return;
         }
-        mActiveSource.invalidate();
+        getActiveSource().invalidate();
         if (!mService.isControlEnabled()) {
             setActivePortId(portId);
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
@@ -452,17 +453,6 @@
         return Constants.ADDR_INVALID;
     }
 
-    private static void invokeCallback(IHdmiControlCallback callback, int result) {
-        if (callback == null) {
-            return;
-        }
-        try {
-            callback.onComplete(result);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Invoking callback failed:" + e);
-        }
-    }
-
     @Override
     @ServiceThreadOnly
     protected boolean handleActiveSource(HdmiCecMessage message) {
@@ -518,7 +508,7 @@
         } else {
             // No HDMI port to switch to was found. Notify the input change listers to
             // switch to the lastly shown internal input.
-            mActiveSource.invalidate();
+            getActiveSource().invalidate();
             setActivePath(Constants.INVALID_PHYSICAL_ADDRESS);
             mService.invokeInputChangeListener(HdmiDeviceInfo.INACTIVE_DEVICE);
         }
@@ -685,7 +675,7 @@
         byte[] params = message.getParams();
         int currentPath = HdmiUtils.twoBytesToInt(params);
         if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) {
-            mActiveSource.invalidate();
+            getActiveSource().invalidate();
             removeAction(RoutingControlAction.class);
             int newPath = HdmiUtils.twoBytesToInt(params, 2);
             addAndStartAction(new RoutingControlAction(this, newPath, true, null));
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 941c321..3f949ba 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -365,6 +365,20 @@
     }
 
     /**
+     * Build &lt;Routing Information&gt; command.
+     *
+     * <p>This is a broadcast message sent to all devices on the bus.
+     *
+     * @param src source address of command
+     * @param physicalAddress physical address of the new active routing path
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildRoutingInformation(int src, int physicalAddress) {
+        return buildCommand(src, Constants.ADDR_BROADCAST,
+            Constants.MESSAGE_ROUTING_INFORMATION, physicalAddressToParam(physicalAddress));
+    }
+
+    /**
      * Build &lt;Give Device Power Status&gt; command.
      *
      * @param src source address of command
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index e3a4084..833091d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -140,6 +140,14 @@
     static final int STANDBY_SCREEN_OFF = 0;
     static final int STANDBY_SHUTDOWN = 1;
 
+    // Logical address of the active source.
+    @GuardedBy("mLock")
+    protected final ActiveSource mActiveSource = new ActiveSource();
+
+    private static final boolean isHdmiCecNeverClaimPlaybackLogicAddr =
+            SystemProperties.getBoolean(
+                    Constants.PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS, false);
+
     /**
      * Interface to report send result.
      */
@@ -413,7 +421,7 @@
         mSettingsObserver = new SettingsObserver(mHandler);
     }
 
-    private static List<Integer> getIntList(String string) {
+    protected static List<Integer> getIntList(String string) {
         ArrayList<Integer> list = new ArrayList<>();
         TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
         splitter.setString(string);
@@ -592,11 +600,6 @@
                     }
                     // No need to propagate to HAL.
                     break;
-                case Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED:
-                    if (isAudioSystemDevice()) {
-                        audioSystem().setAutoTvOff(enabled);
-                    }
-                    break;
                 case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED:
                     if (isTvDeviceEnabled()) {
                         tv().setSystemAudioControlFeatureEnabled(enabled);
@@ -639,6 +642,10 @@
         // A container for [Device type, Local device info].
         ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
         for (int type : mLocalDevices) {
+            if (type == HdmiDeviceInfo.DEVICE_PLAYBACK
+                    && isHdmiCecNeverClaimPlaybackLogicAddr) {
+                continue;
+            }
             HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
             if (localDevice == null) {
                 localDevice = HdmiCecLocalDevice.create(this, type);
@@ -1001,8 +1008,16 @@
         assertRunOnServiceThread();
 
         if (connected && !isTvDevice()) {
+            if (getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT && isSwitchDevice()) {
+                initPortInfo();
+                HdmiLogger.debug("initPortInfo for switch device when onHotplug from tx.");
+            }
             ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
             for (int type : mLocalDevices) {
+                if (type == HdmiDeviceInfo.DEVICE_PLAYBACK
+                        && isHdmiCecNeverClaimPlaybackLogicAddr) {
+                    continue;
+                }
                 HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
                 if (localDevice == null) {
                     localDevice = HdmiCecLocalDevice.create(this, type);
@@ -1382,17 +1397,24 @@
                         return;
                     }
                     HdmiCecLocalDeviceTv tv = tv();
-                    if (tv == null) {
-                        if (!mAddressAllocated) {
-                            mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect(
-                                    HdmiControlService.this, portId, callback));
-                            return;
-                        }
-                        Slog.w(TAG, "Local tv device not available");
-                        invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
+                    if (tv != null) {
+                        tv.doManualPortSwitching(portId, callback);
                         return;
                     }
-                    tv.doManualPortSwitching(portId, callback);
+                    HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                    if (audioSystem != null) {
+                        audioSystem.doManualPortSwitching(portId, callback);
+                        return;
+                    }
+
+                    if (!mAddressAllocated) {
+                        mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect(
+                                HdmiControlService.this, portId, callback));
+                        return;
+                    }
+                    Slog.w(TAG, "Local device not available");
+                    invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
+                    return;
                 }
             });
         }
@@ -1651,6 +1673,9 @@
                     }
                     HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType);
                     if (device == null) {
+                        device = audioSystem();
+                    }
+                    if (device == null) {
                         Slog.w(TAG, "Local device not available");
                         return;
                     }
@@ -1830,9 +1855,13 @@
     @ServiceThreadOnly
     private void oneTouchPlay(final IHdmiControlCallback callback) {
         assertRunOnServiceThread();
-        HdmiCecLocalDevicePlayback source = playback();
+        HdmiCecLocalDeviceSource source = playback();
         if (source == null) {
-            Slog.w(TAG, "Local playback device not available");
+            source = audioSystem();
+        }
+
+        if (source == null) {
+            Slog.w(TAG, "Local source device not available");
             invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
             return;
         }
@@ -2095,11 +2124,20 @@
         return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
     }
 
+    boolean isPlaybackDevice() {
+        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_PLAYBACK);
+    }
+
+    boolean isSwitchDevice() {
+        return SystemProperties.getBoolean(
+            Constants.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+    }
+
     boolean isTvDeviceEnabled() {
         return isTvDevice() && tv() != null;
     }
 
-    private HdmiCecLocalDevicePlayback playback() {
+    protected HdmiCecLocalDevicePlayback playback() {
         return (HdmiCecLocalDevicePlayback)
                 mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK);
     }
@@ -2470,6 +2508,77 @@
         setLastInputForMhl(Constants.INVALID_PORT_ID);
     }
 
+    ActiveSource getActiveSource() {
+        synchronized (mLock) {
+            return mActiveSource;
+        }
+    }
+
+    void setActiveSource(int logicalAddress, int physicalAddress) {
+        synchronized (mLock) {
+            mActiveSource.logicalAddress = logicalAddress;
+            mActiveSource.physicalAddress = physicalAddress;
+        }
+    }
+
+    // This method should only be called when the device can be the active source
+    // and all the device types call into this method.
+    // For example, when receiving broadcast messages, all the device types will call this
+    // method but only one of them will be the Active Source.
+    protected void setAndBroadcastActiveSource(
+            HdmiCecMessage message, int physicalAddress, int deviceType) {
+        // If the device has both playback and audio system logical addresses,
+        // playback will claim active source. Otherwise audio system will.
+        if (deviceType == HdmiDeviceInfo.DEVICE_PLAYBACK) {
+            HdmiCecLocalDevicePlayback playback = playback();
+            playback.setIsActiveSource(true);
+            playback.wakeUpIfActiveSource();
+            playback.maySendActiveSource(message.getSource());
+            setActiveSource(playback.mAddress, physicalAddress);
+        }
+
+        if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
+            HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+            if (playback() != null) {
+                audioSystem.setIsActiveSource(false);
+            } else {
+                audioSystem.setIsActiveSource(true);
+                audioSystem.wakeUpIfActiveSource();
+                audioSystem.maySendActiveSource(message.getSource());
+                setActiveSource(audioSystem.mAddress, physicalAddress);
+            }
+        }
+    }
+
+    // This method should only be called when the device can be the active source
+    // and only one of the device types calls into this method.
+    // For example, when receiving One Touch Play, only playback device handles it
+    // and this method updates Active Source in all the device types sharing the same
+    // Physical Address.
+    protected void setAndBroadcastActiveSourceFromOneDeviceType(
+            int sourceAddress, int physicalAddress) {
+        // If the device has both playback and audio system logical addresses,
+        // playback will claim active source. Otherwise audio system will.
+        HdmiCecLocalDevicePlayback playback = playback();
+        HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+        if (playback != null) {
+            playback.setIsActiveSource(true);
+            playback.wakeUpIfActiveSource();
+            playback.maySendActiveSource(sourceAddress);
+            if (audioSystem != null) {
+                audioSystem.setIsActiveSource(false);
+            }
+            setActiveSource(playback.mAddress, physicalAddress);
+        } else {
+            if (audioSystem != null) {
+                audioSystem.setIsActiveSource(true);
+                audioSystem.wakeUpIfActiveSource();
+                audioSystem.maySendActiveSource(sourceAddress);
+                setActiveSource(audioSystem.mAddress, physicalAddress);
+            }
+        }
+    }
+
     @ServiceThreadOnly
     void setLastInputForMhl(int portId) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 5c66316..41bf01f 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -16,8 +16,8 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
+import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
 import android.util.Slog;
 
@@ -55,7 +55,7 @@
     private int mPowerStatusCounter = 0;
 
     // Factory method. Ensures arguments are valid.
-    static OneTouchPlayAction create(HdmiCecLocalDevicePlayback source,
+    static OneTouchPlayAction create(HdmiCecLocalDeviceSource source,
             int targetAddress, IHdmiControlCallback callback) {
         if (source == null || callback == null) {
             Slog.e(TAG, "Wrong arguments");
@@ -83,9 +83,17 @@
     }
 
     private void broadcastActiveSource() {
-        sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), getSourcePath()));
-        // Because only playback device can create this action, it's safe to cast.
-        playback().setActiveSource(true);
+        // Because only source device can create this action, it's safe to cast.
+        HdmiCecLocalDeviceSource source = source();
+        source.mService.setAndBroadcastActiveSourceFromOneDeviceType(
+                mTargetAddress, getSourcePath());
+        // Set local active port to HOME when One Touch Play.
+        // Active Port and Current Input are handled by the switch functionality device.
+        if (source.mService.audioSystem() != null) {
+            source = source.mService.audioSystem();
+        }
+        source.setRoutingPort(Constants.CEC_SWITCH_HOME);
+        source.setLocalActivePort(Constants.CEC_SWITCH_HOME);
     }
 
     private void queryDevicePowerStatus() {
diff --git a/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java b/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
index 75986c7..ba16260 100644
--- a/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
+++ b/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
@@ -56,6 +56,10 @@
             return mService.tv();
         }
 
+        protected HdmiCecLocalDeviceAudioSystem audioSystem() {
+            return mService.audioSystem();
+        }
+
         protected boolean isLocalDeviceReady() {
             if (tv() == null) {
                 Slog.e(TAG, "Local tv device not available");
@@ -105,7 +109,15 @@
         public void process() {
             if (isLocalDeviceReady()) {
                 Slog.v(TAG, "calling delayed portSelect id:" + mId);
-                tv().doManualPortSwitching(mId, mCallback);
+                HdmiCecLocalDeviceTv tv = tv();
+                if (tv != null) {
+                    tv.doManualPortSwitching(mId, mCallback);
+                    return;
+                }
+                HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                if (audioSystem != null) {
+                    audioSystem.doManualPortSwitching(mId, mCallback);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index 2fdcb51..b6ebcd7c 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -16,6 +16,7 @@
 package com.android.server.hdmi;
 
 import android.hardware.tv.cec.V1_0.SendMessageResult;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 /**
@@ -40,7 +41,7 @@
 
     @Override
     boolean start() {
-        if (audioSystem().mActiveSource.physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
+        if (audioSystem().getActiveSource().physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
             mState = STATE_WAITING_FOR_ACTIVE_SOURCE;
             addTimer(mState, HdmiConfig.TIMEOUT_MS);
             sendRequestActiveSource();
@@ -59,10 +60,8 @@
                     return false;
                 }
                 mActionTimer.clearTimerMessage();
-                int physicalAddress = HdmiUtils.twoBytesToInt(cmd.getParams());
-                if (physicalAddress != getSourcePath()) {
-                    audioSystem().setActiveSource(cmd.getSource(), physicalAddress);
-                }
+                // Broadcast message is also handled by other device types
+                audioSystem().handleActiveSource(cmd);
                 mState = STATE_WAITING_FOR_TV_SUPPORT;
                 queryTvSystemAudioModeSupport();
                 return true;
@@ -91,7 +90,7 @@
                             mSendRequestActiveSourceRetryCount++;
                             sendRequestActiveSource();
                         } else {
-                            audioSystem().setSystemAudioMode(false);
+                            audioSystem().checkSupportAndSetSystemAudioMode(false);
                             finish();
                         }
                     }
@@ -106,7 +105,7 @@
                             mSendSetSystemAudioModeRetryCount++;
                             sendSetSystemAudioMode(on, dest);
                         } else {
-                            audioSystem().setSystemAudioMode(false);
+                            audioSystem().checkSupportAndSetSystemAudioMode(false);
                             finish();
                         }
                     }
@@ -115,7 +114,16 @@
 
     private void handleActiveSourceTimeout() {
         HdmiLogger.debug("Cannot get active source.");
-        audioSystem().setSystemAudioMode(false);
+        // If not able to find Active Source and the current device has playbcak functionality,
+        // claim Active Source and start to query TV system audio mode support.
+        if (audioSystem().mService.isPlaybackDevice()) {
+            audioSystem().mService.setAndBroadcastActiveSourceFromOneDeviceType(
+                    Constants.ADDR_BROADCAST, getSourcePath());
+            mState = STATE_WAITING_FOR_TV_SUPPORT;
+            queryTvSystemAudioModeSupport();
+        } else {
+            audioSystem().checkSupportAndSetSystemAudioMode(false);
+        }
         finish();
     }
 
@@ -123,12 +131,12 @@
         audioSystem().queryTvSystemAudioModeSupport(
                 supported -> {
                     if (supported) {
-                        if (audioSystem().setSystemAudioMode(true)) {
+                        if (audioSystem().checkSupportAndSetSystemAudioMode(true)) {
                             sendSetSystemAudioMode(true, Constants.ADDR_BROADCAST);
                         }
                         finish();
                     } else {
-                        audioSystem().setSystemAudioMode(false);
+                        audioSystem().checkSupportAndSetSystemAudioMode(false);
                         finish();
                     }
                 });
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index e7c3c7b..df28f30 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -213,8 +213,6 @@
     private static native void nativeSetFocusedApplication(long ptr,
             int displayId, InputApplicationHandle application);
     private static native void nativeSetFocusedDisplay(long ptr, int displayId);
-    private static native boolean nativeTransferTouchFocus(long ptr,
-            InputChannel fromChannel, InputChannel toChannel);
     private static native void nativeSetPointerSpeed(long ptr, int speed);
     private static native void nativeSetShowTouches(long ptr, boolean enabled);
     private static native void nativeSetInteractive(long ptr, boolean interactive);
@@ -1485,29 +1483,6 @@
         nativeSetSystemUiVisibility(mPtr, visibility);
     }
 
-    /**
-     * Atomically transfers touch focus from one window to another as identified by
-     * their input channels.  It is possible for multiple windows to have
-     * touch focus if they support split touch dispatch
-     * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
-     * method only transfers touch focus of the specified window without affecting
-     * other windows that may also have touch focus at the same time.
-     * @param fromChannel The channel of a window that currently has touch focus.
-     * @param toChannel The channel of the window that should receive touch focus in
-     * place of the first.
-     * @return True if the transfer was successful.  False if the window with the
-     * specified channel did not actually have touch focus at the time of the request.
-     */
-    public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
-        if (fromChannel == null) {
-            throw new IllegalArgumentException("fromChannel must not be null.");
-        }
-        if (toChannel == null) {
-            throw new IllegalArgumentException("toChannel must not be null.");
-        }
-        return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
-    }
-
     @Override // Binder call
     public void tryPointerSpeed(int speed) {
         if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
@@ -1785,15 +1760,14 @@
     }
 
     // Native callback
-    private void notifyFocusChanged(IBinder token) {
-        if (mFocusedWindow != token) {
-            if (mFocusedWindowHasCapture) {
-                setPointerCapture(false);
-            }
-            if (token instanceof IWindow) {
-                mFocusedWindow = (IWindow) token;
-            }
+    private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
+        if (mFocusedWindow.asBinder() == newToken) {
+            Log.w(TAG, "notifyFocusChanged called with unchanged mFocusedWindow=" + mFocusedWindow);
+            return;
         }
+
+        setPointerCapture(false);
+        mFocusedWindow = IWindow.Stub.asInterface(newToken);
     }
 
     // Native callback.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 3264790..d4b8eb2 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -16,7 +16,15 @@
 
 package com.android.server.inputmethod;
 
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.content.ComponentName;
+import android.view.inputmethod.InputMethodInfo;
+
+import com.android.server.LocalServices;
+
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Input method manager local system service interface.
@@ -39,9 +47,25 @@
     public abstract void startVrInputMethodNoCheck(ComponentName componentName);
 
     /**
+     * Returns the list of installed input methods for the specified user.
+     *
+     * @param userId The user ID to be queried.
+     * @return A list of {@link InputMethodInfo}.  VR-only IMEs are already excluded.
+     */
+    public abstract List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
+
+    /**
+     * Returns the list of installed input methods that are enabled for the specified user.
+     *
+     * @param userId The user ID to be queried.
+     * @return A list of {@link InputMethodInfo} that are enabled for {@code userId}.
+     */
+    public abstract List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId);
+
+    /**
      * Fake implementation of {@link InputMethodManagerInternal}.  All the methods do nothing.
      */
-    public static final InputMethodManagerInternal NOP =
+    private static final InputMethodManagerInternal NOP =
             new InputMethodManagerInternal() {
                 @Override
                 public void setInteractive(boolean interactive) {
@@ -54,5 +78,25 @@
                 @Override
                 public void startVrInputMethodNoCheck(ComponentName componentName) {
                 }
+
+                @Override
+                public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
+                    return Collections.emptyList();
+                }
+
+                @Override
+                public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
+                    return Collections.emptyList();
+                }
             };
+
+    /**
+     * @return Global instance if exists.  Otherwise, a dummy no-op instance.
+     */
+    @NonNull
+    public static InputMethodManagerInternal get() {
+        final InputMethodManagerInternal instance =
+                LocalServices.getService(InputMethodManagerInternal.class);
+        return instance != null ? instance : NOP;
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d45869e..5fa3f52 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.inputmethod.InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -1603,7 +1604,7 @@
     // 1) it comes from the system process
     // 2) the calling process' user id is identical to the current user id IMMS thinks.
     @GuardedBy("mMethodMap")
-    private boolean calledFromValidUserLocked() {
+    private boolean calledFromValidUserLocked(boolean allowCrossProfileAccess) {
         final int uid = Binder.getCallingUid();
         final int userId = UserHandle.getUserId(uid);
         if (DEBUG) {
@@ -1613,7 +1614,13 @@
                     + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
                     + InputMethodUtils.getApiCallStack());
         }
-        if (uid == Process.SYSTEM_UID || mSettings.isCurrentProfile(userId)) {
+        if (uid == Process.SYSTEM_UID) {
+            return true;
+        }
+        if (userId == mSettings.getCurrentUserId()) {
+            return true;
+        }
+        if (allowCrossProfileAccess && mSettings.isCurrentProfile(userId)) {
             return true;
         }
 
@@ -1674,40 +1681,93 @@
 
     @Override
     public List<InputMethodInfo> getInputMethodList() {
-        return getInputMethodList(false /* isVrOnly */);
+        final int callingUserId = UserHandle.getCallingUserId();
+        synchronized (mMethodMap) {
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                    mSettings.getCurrentUserId(), null);
+            if (resolvedUserIds.length != 1) {
+                return Collections.emptyList();
+            }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getInputMethodListLocked(false /* isVrOnly */, resolvedUserIds[0]);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 
     @Override
     public List<InputMethodInfo> getVrInputMethodList() {
-        return getInputMethodList(true /* isVrOnly */);
-    }
-
-    private List<InputMethodInfo> getInputMethodList(final boolean isVrOnly) {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                    mSettings.getCurrentUserId(), null);
+            if (resolvedUserIds.length != 1) {
                 return Collections.emptyList();
             }
-            ArrayList<InputMethodInfo> methodList = new ArrayList<>();
-            for (InputMethodInfo info : mMethodList) {
-
-                if (info.isVrOnly() == isVrOnly) {
-                    methodList.add(info);
-                }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getInputMethodListLocked(true /* isVrOnly */, resolvedUserIds[0]);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-            return methodList;
         }
     }
 
     @Override
     public List<InputMethodInfo> getEnabledInputMethodList() {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                    mSettings.getCurrentUserId(), null);
+            if (resolvedUserIds.length != 1) {
                 return Collections.emptyList();
             }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getEnabledInputMethodListLocked(resolvedUserIds[0]);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @GuardedBy("mMethodMap")
+    private List<InputMethodInfo> getInputMethodListLocked(boolean isVrOnly,
+            @UserIdInt int userId) {
+        final ArrayList<InputMethodInfo> methodList;
+        if (userId == mSettings.getCurrentUserId()) {
+            // Create a copy.
+            methodList = new ArrayList<>(mMethodList);
+        } else {
+            final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+            methodList = new ArrayList<>();
+            final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+                    new ArrayMap<>();
+            AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+            queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+                    methodList);
+        }
+        methodList.removeIf(imi -> imi.isVrOnly() != isVrOnly);
+        return methodList;
+    }
+
+    @GuardedBy("mMethodMap")
+    private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
+        if (userId == mSettings.getCurrentUserId()) {
             return mSettings.getEnabledInputMethodListLocked();
         }
+        final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+        final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+        final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+                new ArrayMap<>();
+        AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+        queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+                methodList);
+        final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
+                mContext.getContentResolver(), methodMap, methodList, userId, true);
+        return settings.getEnabledInputMethodListLocked();
     }
 
     /**
@@ -1717,11 +1777,27 @@
     @Override
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
             boolean allowsImplicitlySelectedSubtypes) {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                    mSettings.getCurrentUserId(), null);
+            if (resolvedUserIds.length != 1) {
                 return Collections.emptyList();
             }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getEnabledInputMethodSubtypeListLocked(imiId,
+                        allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @GuardedBy("mMethodMap")
+    private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
+            boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
+        if (userId == mSettings.getCurrentUserId()) {
             final InputMethodInfo imi;
             if (imiId == null && mCurMethodId != null) {
                 imi = mMethodMap.get(mCurMethodId);
@@ -1734,6 +1810,21 @@
             return mSettings.getEnabledInputMethodSubtypeListLocked(
                     mContext, imi, allowsImplicitlySelectedSubtypes);
         }
+        final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+        final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+        final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+                new ArrayMap<>();
+        AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+        queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+                methodList);
+        final InputMethodInfo imi = methodMap.get(imiId);
+        if (imi == null) {
+            return Collections.emptyList();
+        }
+        final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
+                mContext.getContentResolver(), methodMap, methodList, userId, true);
+        return settings.getEnabledInputMethodSubtypeListLocked(
+                mContext, imi, allowsImplicitlySelectedSubtypes);
     }
 
     /**
@@ -2434,7 +2525,7 @@
     @Override
     public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return;
             }
             final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
@@ -2450,7 +2541,7 @@
     @Override
     public boolean notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return false;
             }
             final InputMethodInfo targetImi = mSecureSuggestionSpans.get(span);
@@ -2617,7 +2708,7 @@
             ResultReceiver resultReceiver) {
         int uid = Binder.getCallingUid();
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return false;
             }
             final long ident = Binder.clearCallingIdentity();
@@ -2702,7 +2793,7 @@
             ResultReceiver resultReceiver) {
         int uid = Binder.getCallingUid();
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return false;
             }
             final long ident = Binder.clearCallingIdentity();
@@ -2809,10 +2900,12 @@
             @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
             IInputContext inputContext, @MissingMethodFlags int missingMethods,
             int unverifiedTargetSdkVersion) {
+        final int userId = UserHandle.getUserId(Binder.getCallingUid());
         InputBindResult res = null;
         synchronized (mMethodMap) {
             // Needs to check the validity before clearing calling identity
-            final boolean calledFromValidUser = calledFromValidUserLocked();
+            // Note that cross-profile access is always allowed here to allow profile-switching.
+            final boolean calledFromValidUser = calledFromValidUserLocked(true);
             final int windowDisplayId =
                     mWindowManagerInternal.getDisplayIdForWindow(windowToken);
             final long ident = Binder.clearCallingIdentity();
@@ -2864,6 +2957,10 @@
                     return InputBindResult.INVALID_USER;
                 }
 
+                if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
+                    switchUserLocked(userId);
+                }
+
                 if (mCurFocusedWindow == windowToken) {
                     if (DEBUG) {
                         Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
@@ -3032,7 +3129,7 @@
     public void showInputMethodPickerFromClient(
             IInputMethodClient client, int auxiliarySubtypeMode) {
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return;
             }
             if(!canShowInputMethodPickerLocked(client)) {
@@ -3103,7 +3200,7 @@
             IInputMethodClient client, String inputMethodId) {
         synchronized (mMethodMap) {
             // TODO(yukawa): Should we verify the display ID?
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return;
             }
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
@@ -3218,7 +3315,7 @@
     @Override
     public InputMethodSubtype getLastInputMethodSubtype() {
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return null;
             }
             final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
@@ -3256,7 +3353,7 @@
             }
         }
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return;
             }
             if (!mSystemReady) {
@@ -4102,7 +4199,7 @@
     public InputMethodSubtype getCurrentInputMethodSubtype() {
         synchronized (mMethodMap) {
             // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return null;
             }
             return getCurrentInputMethodSubtypeLocked();
@@ -4152,7 +4249,7 @@
     public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
         synchronized (mMethodMap) {
             // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            if (!calledFromValidUserLocked(!PER_PROFILE_IME_ENABLED)) {
                 return false;
             }
             if (subtype != null && mCurMethodId != null) {
@@ -4167,6 +4264,18 @@
         }
     }
 
+    private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
+        synchronized (mMethodMap) {
+            return getInputMethodListLocked(false, userId);
+        }
+    }
+
+    private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
+        synchronized (mMethodMap) {
+            return getEnabledInputMethodListLocked(userId);
+        }
+    }
+
     private static final class LocalServiceImpl extends InputMethodManagerInternal {
         @NonNull
         private final InputMethodManagerService mService;
@@ -4192,6 +4301,16 @@
         public void startVrInputMethodNoCheck(@Nullable ComponentName componentName) {
             mService.mHandler.obtainMessage(MSG_START_VR_INPUT, componentName).sendToTarget();
         }
+
+        @Override
+        public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
+            return mService.getInputMethodListAsUser(userId);
+        }
+
+        @Override
+        public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
+            return mService.getEnabledInputMethodListAsUser(userId);
+        }
     }
 
     @BinderThread
@@ -4545,6 +4664,7 @@
     private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
         boolean all = false;
         boolean brief = false;
+        int userIdToBeResolved = UserHandle.USER_CURRENT;
         while (true) {
             final String nextOption = shellCommand.getNextOption();
             if (nextOption == null) {
@@ -4557,19 +4677,34 @@
                 case "-s":
                     brief = true;
                     break;
+                case "-u":
+                case "--user":
+                    userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
+                    break;
             }
         }
-        final List<InputMethodInfo> methods = all ?
-                getInputMethodList() : getEnabledInputMethodList();
-        final PrintWriter pr = shellCommand.getOutPrintWriter();
-        final Printer printer = x -> pr.println(x);
-        final int N = methods.size();
-        for (int i = 0; i < N; ++i) {
-            if (brief) {
-                pr.println(methods.get(i).getId());
-            } else {
-                pr.print(methods.get(i).getId()); pr.println(":");
-                methods.get(i).dump(printer, "  ");
+        synchronized (mMethodMap) {
+            final PrintWriter pr = shellCommand.getOutPrintWriter();
+            final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+                    mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+            for (int userId : userIds) {
+                final List<InputMethodInfo> methods = all
+                        ? getInputMethodListLocked(false, userId)
+                        : getEnabledInputMethodListLocked(userId);
+                if (userIds.length > 1) {
+                    pr.print("User #");
+                    pr.print(userId);
+                    pr.println(":");
+                }
+                for (InputMethodInfo info : methods) {
+                    if (brief) {
+                        pr.println(info.getId());
+                    } else {
+                        pr.print(info.getId());
+                        pr.println(":");
+                        info.dump(pr::println, "  ");
+                    }
+                }
             }
         }
         return ShellCommandResult.SUCCESS;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 1137bf9..88d1a9c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -29,21 +29,27 @@
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.IntArray;
 import android.util.Pair;
 import android.util.Printer;
 import android.util.Slog;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
+import android.view.inputmethod.InputMethodSystemProperty;
 import android.view.textservice.SpellCheckerInfo;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.StartInputFlags;
+import com.android.server.LocalServices;
 import com.android.server.textservices.TextServicesManagerInternal;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashSet;
@@ -1286,4 +1292,62 @@
         return true;
     }
 
+    /**
+     * Converts a user ID, which can be a pseudo user ID such as {@link UserHandle#USER_ALL} to a
+     * list of real user IDs.
+     *
+     * <p>This method also converts profile user ID to profile parent user ID unless
+     * {@link InputMethodSystemProperty#PER_PROFILE_IME_ENABLED} is {@code true}.</p>
+     *
+     * @param userIdToBeResolved A user ID. Two pseudo user ID {@link UserHandle#USER_CURRENT} and
+     *                           {@link UserHandle#USER_ALL} are also supported
+     * @param currentUserId A real user ID, which will be used when {@link UserHandle#USER_CURRENT}
+     *                      is specified in {@code userIdToBeResolved}.
+     * @param warningWriter A {@link PrintWriter} to output some debug messages. {@code null} if
+     *                      no debug message is required.
+     * @return An integer array that contain user IDs.
+     */
+    static int[] resolveUserId(@UserIdInt int userIdToBeResolved,
+            @UserIdInt int currentUserId, @Nullable PrintWriter warningWriter) {
+        final UserManagerInternal userManagerInternal =
+                LocalServices.getService(UserManagerInternal.class);
+
+        if (userIdToBeResolved == UserHandle.USER_ALL) {
+            if (InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+                return userManagerInternal.getUserIds();
+            }
+            final IntArray result = new IntArray();
+            for (int userId : userManagerInternal.getUserIds()) {
+                final int parentUserId = userManagerInternal.getProfileParentId(userId);
+                if (result.indexOf(parentUserId) < 0) {
+                    result.add(parentUserId);
+                }
+            }
+            return result.toArray();
+        }
+
+        final int sourceUserId;
+        if (userIdToBeResolved == UserHandle.USER_CURRENT) {
+            sourceUserId = currentUserId;
+        } else if (userIdToBeResolved < 0) {
+            if (warningWriter != null) {
+                warningWriter.print("Pseudo user ID ");
+                warningWriter.print(userIdToBeResolved);
+                warningWriter.println(" is not supported.");
+            }
+            return new int[]{};
+        } else if (userManagerInternal.exists(userIdToBeResolved)) {
+            sourceUserId = userIdToBeResolved;
+        } else {
+            if (warningWriter != null) {
+                warningWriter.print("User #");
+                warningWriter.print(userIdToBeResolved);
+                warningWriter.println(" does not exit.");
+            }
+            return new int[]{};
+        }
+        final int resolvedUserId = InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
+                ? sourceUserId : userManagerInternal.getProfileParentId(sourceUserId);
+        return new int[]{resolvedUserId};
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 98ed3ea..f304ceb 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -163,6 +163,18 @@
                         public void startVrInputMethodNoCheck(ComponentName componentName) {
                             reportNotSupported();
                         }
+
+                        @Override
+                        public List<InputMethodInfo> getInputMethodListAsUser(
+                                @UserIdInt int userId) {
+                            return userIdToInputMethodInfoMapper.getAsList(userId);
+                        }
+
+                        @Override
+                        public List<InputMethodInfo> getEnabledInputMethodListAsUser(
+                                @UserIdInt int userId) {
+                            return userIdToInputMethodInfoMapper.getAsList(userId);
+                        }
                     });
         }
 
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 4c7c420..b3f1018 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /**
- * Location Manager's interface for location providers.
+ * Location Manager's interface for location providers. Always starts as disabled.
  *
  * @hide
  */
@@ -41,12 +41,6 @@
     public interface LocationProviderManager {
 
         /**
-         * Called on location provider construction to make the location service aware of this
-         * provider and what it's initial enabled/disabled state should be.
-         */
-        void onAttachProvider(AbstractLocationProvider locationProvider, boolean initiallyEnabled);
-
-        /**
          * May be called to inform the location service of a change in this location provider's
          * enabled/disabled state.
          */
@@ -74,13 +68,7 @@
     private final LocationProviderManager mLocationProviderManager;
 
     protected AbstractLocationProvider(LocationProviderManager locationProviderManager) {
-        this(locationProviderManager, true);
-    }
-
-    protected AbstractLocationProvider(LocationProviderManager locationProviderManager,
-            boolean initiallyEnabled) {
         mLocationProviderManager = locationProviderManager;
-        mLocationProviderManager.onAttachProvider(this, initiallyEnabled);
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 3c81a45..269767a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -559,7 +559,7 @@
 
     public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
             Looper looper) {
-        super(locationProviderManager, true);
+        super(locationProviderManager);
 
         mContext = context;
 
@@ -652,6 +652,7 @@
         }, UserHandle.ALL, intentFilter, null, mHandler);
 
         setProperties(PROPERTIES);
+        setEnabled(true);
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index dfcef70..a6da8c5 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -101,7 +101,7 @@
     private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager,
             String action, int overlaySwitchResId, int defaultServicePackageNameResId,
             int initialPackageNamesResId) {
-        super(locationProviderManager, false);
+        super(locationProviderManager);
 
         mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
                 defaultServicePackageNameResId, initialPackageNamesResId,
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index b7934d9..b7ccb26 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -123,6 +123,9 @@
         // in foreground.
         private long mForegroundDurationMs;
 
+        // Time when package last went dormant (stopped requesting location)
+        private long mLastStopElapsedTimeMs;
+
         private PackageStatistics() {
             mInitialElapsedTimeMs = SystemClock.elapsedRealtime();
             mNumActiveRequests = 0;
@@ -131,6 +134,7 @@
             mSlowestIntervalMs = 0;
             mForegroundDurationMs = 0;
             mLastForegroundElapsedTimeMs = 0;
+            mLastStopElapsedTimeMs = 0;
         }
 
         private void startRequesting(long intervalMs) {
@@ -167,8 +171,8 @@
 
             mNumActiveRequests--;
             if (mNumActiveRequests == 0) {
-                long lastDurationMs
-                        = SystemClock.elapsedRealtime() - mLastActivitationElapsedTimeMs;
+                mLastStopElapsedTimeMs = SystemClock.elapsedRealtime();
+                long lastDurationMs = mLastStopElapsedTimeMs - mLastActivitationElapsedTimeMs;
                 mTotalDurationMs += lastDurationMs;
                 updateForeground(false);
             }
@@ -206,6 +210,13 @@
         }
 
         /**
+         * Returns the time since the last request stopped in ms.
+         */
+        public long getTimeSinceLastRequestStoppedMs() {
+            return SystemClock.elapsedRealtime() - mLastStopElapsedTimeMs;
+        }
+
+        /**
          * Returns the fastest interval that has been tracked.
          */
         public long getFastestIntervalMs() {
@@ -244,6 +255,10 @@
                     .append(" minutes");
             if (isActive()) {
                 s.append(": Currently active");
+            } else {
+                s.append(": Last active ")
+                        .append((getTimeSinceLastRequestStoppedMs() / 1000) / 60)
+                        .append(" minutes ago");
             }
             return s.toString();
         }
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index bfbebf7..86bc9f3 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -43,7 +43,7 @@
 
     public MockProvider(
             LocationProviderManager locationProviderManager, ProviderProperties properties) {
-        super(locationProviderManager, true);
+        super(locationProviderManager);
 
         mEnabled = true;
         mLocation = null;
@@ -52,6 +52,7 @@
         mExtras = null;
 
         setProperties(properties);
+        setEnabled(true);
     }
 
     /** Sets the enabled state of this mock provider. */
@@ -63,8 +64,11 @@
     /** Sets the location to report for this mock provider. */
     public void setLocation(Location l) {
         mLocation = new Location(l);
+        if (!mLocation.isFromMockProvider()) {
+            mLocation.setIsFromMockProvider(true);
+        }
         if (mEnabled) {
-            reportLocation(l);
+            reportLocation(mLocation);
         }
     }
 
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 70d64b0..30260b2 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -43,11 +43,12 @@
     private boolean mReportLocation;
 
     public PassiveProvider(LocationProviderManager locationProviderManager) {
-        super(locationProviderManager, true);
+        super(locationProviderManager);
 
         mReportLocation = false;
 
         setProperties(PROPERTIES);
+        setEnabled(true);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b70c64e..d611a17 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -19,7 +19,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
@@ -27,14 +26,15 @@
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
+import android.media.session.ControllerCallbackLink;
 import android.media.session.ISession;
-import android.media.session.ISessionCallback;
 import android.media.session.ISessionController;
-import android.media.session.ISessionControllerCallback;
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
 import android.media.session.MediaSession;
+import android.media.session.MediaSession.QueueItem;
 import android.media.session.PlaybackState;
+import android.media.session.SessionCallbackLink;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -44,7 +44,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.util.Log;
@@ -55,6 +54,7 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This is the system implementation of a Session. Apps will interact with the
@@ -84,7 +84,7 @@
     private final Context mContext;
 
     private final Object mLock = new Object();
-    private final ArrayList<ISessionControllerCallbackHolder> mControllerCallbackHolders =
+    private final ArrayList<ControllerCallbackLinkHolder> mControllerCallbackHolders =
             new ArrayList<>();
 
     private long mFlags;
@@ -97,7 +97,7 @@
     // may result in throwing an exception.
     private MediaMetadata mMetadata;
     private PlaybackState mPlaybackState;
-    private ParceledListSlice mQueue;
+    private List<QueueItem> mQueue;
     private CharSequence mQueueTitle;
     private int mRatingType;
     // End TransportPerformer fields
@@ -116,11 +116,11 @@
     private boolean mIsActive = false;
     private boolean mDestroyed = false;
 
-    private long mDuration;
+    private long mDuration = -1;
     private String mMetadataDescription;
 
     public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
-            ISessionCallback cb, String tag, MediaSessionService service, Looper handlerLooper) {
+            SessionCallbackLink cb, String tag, MediaSessionService service, Looper handlerLooper) {
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
@@ -249,7 +249,7 @@
      * @param useSuggested True to use adjustSuggestedStreamVolume instead of
      */
     public void adjustVolume(String packageName, String opPackageName, int pid, int uid,
-            ISessionControllerCallback caller, boolean asSystemService, int direction, int flags,
+            ControllerCallbackLink caller, boolean asSystemService, int direction, int flags,
             boolean useSuggested) {
         int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
         if (isPlaybackActive() || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
@@ -291,7 +291,7 @@
     }
 
     private void setVolumeTo(String packageName, String opPackageName, int pid, int uid,
-            ISessionControllerCallback caller, int value, int flags) {
+            ControllerCallbackLink caller, int value, int flags) {
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
             final int volumeValue = value;
@@ -440,7 +440,7 @@
         }
     }
 
-    public ISessionCallback getCallback() {
+    public SessionCallbackLink getCallback() {
         return mSessionCb.mCb;
     }
 
@@ -468,7 +468,7 @@
                 + ", max=" + mMaxVolume + ", current=" + mCurrentVolume);
         pw.println(indent + "metadata: " + mMetadataDescription);
         pw.println(indent + "queueTitle=" + mQueueTitle + ", size="
-                + (mQueue == null ? 0 : mQueue.getList().size()));
+                + (mQueue == null ? 0 : mQueue.size()));
     }
 
     @Override
@@ -518,7 +518,7 @@
     }
 
     private void logCallbackException(
-            String msg, ISessionControllerCallbackHolder holder, Exception e) {
+            String msg, ControllerCallbackLinkHolder holder, Exception e) {
         Log.v(TAG, msg + ", this=" + this + ", callback package=" + holder.mPackageName
                 + ", exception=" + e);
     }
@@ -529,16 +529,18 @@
                 return;
             }
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onPlaybackStateChanged(mPlaybackState);
-                } catch (DeadObjectException e) {
-                    mControllerCallbackHolders.remove(i);
-                    logCallbackException("Removed dead callback in pushPlaybackStateUpdate",
-                            holder, e);
-                } catch (RemoteException e) {
-                    logCallbackException("unexpected exception in pushPlaybackStateUpdate",
-                            holder, e);
+                    holder.mCallback.notifyPlaybackStateChanged(mPlaybackState);
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushPlaybackStateUpdate",
+                                holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushPlaybackStateUpdate",
+                                holder, e);
+                    }
                 }
             }
         }
@@ -550,14 +552,18 @@
                 return;
             }
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onMetadataChanged(mMetadata);
-                } catch (DeadObjectException e) {
-                    logCallbackException("Removing dead callback in pushMetadataUpdate", holder, e);
-                    mControllerCallbackHolders.remove(i);
-                } catch (RemoteException e) {
-                    logCallbackException("unexpected exception in pushMetadataUpdate", holder, e);
+                    holder.mCallback.notifyMetadataChanged(mMetadata);
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushMetadataUpdate",
+                                holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushMetadataUpdate",
+                                holder, e);
+                    }
                 }
             }
         }
@@ -569,14 +575,17 @@
                 return;
             }
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onQueueChanged(mQueue);
-                } catch (DeadObjectException e) {
-                    mControllerCallbackHolders.remove(i);
-                    logCallbackException("Removed dead callback in pushQueueUpdate", holder, e);
-                } catch (RemoteException e) {
-                    logCallbackException("unexpected exception in pushQueueUpdate", holder, e);
+                    holder.mCallback.notifyQueueChanged(mQueue);
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushQueueUpdate",
+                                holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushQueueUpdate", holder, e);
+                    }
                 }
             }
         }
@@ -588,16 +597,18 @@
                 return;
             }
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onQueueTitleChanged(mQueueTitle);
-                } catch (DeadObjectException e) {
-                    mControllerCallbackHolders.remove(i);
-                    logCallbackException("Removed dead callback in pushQueueTitleUpdate",
-                            holder, e);
-                } catch (RemoteException e) {
-                    logCallbackException("unexpected exception in pushQueueTitleUpdate",
-                            holder, e);
+                    holder.mCallback.notifyQueueTitleChanged(mQueueTitle);
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushQueueTitleUpdate",
+                                holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushQueueTitleUpdate",
+                                holder, e);
+                    }
                 }
             }
         }
@@ -609,14 +620,17 @@
                 return;
             }
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onExtrasChanged(mExtras);
-                } catch (DeadObjectException e) {
-                    mControllerCallbackHolders.remove(i);
-                    logCallbackException("Removed dead callback in pushExtrasUpdate", holder, e);
-                } catch (RemoteException e) {
-                    logCallbackException("unexpected exception in pushExtrasUpdate", holder, e);
+                    holder.mCallback.notifyExtrasChanged(mExtras);
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushExtrasUpdate",
+                                holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushExtrasUpdate", holder, e);
+                    }
                 }
             }
         }
@@ -629,14 +643,17 @@
             }
             PlaybackInfo info = mController.getVolumeAttributes();
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onVolumeInfoChanged(info);
-                } catch (DeadObjectException e) {
-                    mControllerCallbackHolders.remove(i);
-                    logCallbackException("Removing dead callback in pushVolumeUpdate", holder, e);
-                } catch (RemoteException e) {
-                    logCallbackException("Unexpected exception in pushVolumeUpdate", holder, e);
+                    holder.mCallback.notifyVolumeInfoChanged(info);
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushVolumeUpdate",
+                                holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushVolumeUpdate", holder, e);
+                    }
                 }
             }
         }
@@ -648,14 +665,16 @@
                 return;
             }
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onEvent(event, data);
-                } catch (DeadObjectException e) {
-                    mControllerCallbackHolders.remove(i);
-                    logCallbackException("Removing dead callback in pushEvent", holder, e);
-                } catch (RemoteException e) {
-                    logCallbackException("unexpected exception in pushEvent", holder, e);
+                    holder.mCallback.notifyEvent(event, data);
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushEvent", holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushEvent", holder, e);
+                    }
                 }
             }
         }
@@ -669,14 +688,18 @@
                 return;
             }
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
+                ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.onSessionDestroyed();
-                } catch (DeadObjectException e) {
-                    logCallbackException("Removing dead callback in pushEvent", holder, e);
-                    mControllerCallbackHolders.remove(i);
-                } catch (RemoteException e) {
-                    logCallbackException("unexpected exception in pushEvent", holder, e);
+                    holder.mCallback.notifySessionDestroyed();
+                } catch (RuntimeException e) {
+                    if (e.getCause() instanceof DeadObjectException) {
+                        mControllerCallbackHolders.remove(i);
+                        logCallbackException("Removing dead callback in pushSessionDestroyed",
+                                holder, e);
+                    } else {
+                        logCallbackException("unexpected exception in pushSessionDestroyed",
+                                holder, e);
+                    }
                 }
             }
             // After notifying clear all listeners
@@ -716,10 +739,10 @@
         return result == null ? state : result;
     }
 
-    private int getControllerHolderIndexForCb(ISessionControllerCallback cb) {
-        IBinder binder = cb.asBinder();
+    private int getControllerHolderIndexForCb(ControllerCallbackLink cb) {
+        IBinder binder = cb.getBinder();
         for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
-            if (binder.equals(mControllerCallbackHolders.get(i).mCallback.asBinder())) {
+            if (binder.equals(mControllerCallbackHolders.get(i).mCallback.getBinder())) {
                 return i;
             }
         }
@@ -843,7 +866,7 @@
         }
 
         @Override
-        public void setQueue(ParceledListSlice queue) {
+        public void setQueue(List<QueueItem> queue) {
             synchronized (mLock) {
                 mQueue = queue;
             }
@@ -920,9 +943,9 @@
     }
 
     class SessionCb {
-        private final ISessionCallback mCb;
+        private final SessionCallbackLink mCb;
 
-        public SessionCb(ISessionCallback cb) {
+        SessionCb(SessionCallbackLink cb) {
             mCb = cb;
         }
 
@@ -930,224 +953,224 @@
                 boolean asSystemService, KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
             try {
                 if (asSystemService) {
-                    mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+                    mCb.notifyMediaButton(mContext.getPackageName(), Process.myPid(),
                             Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), sequenceId, cb);
                 } else {
-                    mCb.onMediaButton(packageName, pid, uid,
+                    mCb.notifyMediaButton(packageName, pid, uid,
                             createMediaButtonIntent(keyEvent), sequenceId, cb);
                 }
                 return true;
-            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
             }
             return false;
         }
 
         public boolean sendMediaButton(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, boolean asSystemService,
+                ControllerCallbackLink caller, boolean asSystemService,
                 KeyEvent keyEvent) {
             try {
                 if (asSystemService) {
-                    mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+                    mCb.notifyMediaButton(mContext.getPackageName(), Process.myPid(),
                             Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), 0, null);
                 } else {
-                    mCb.onMediaButtonFromController(packageName, pid, uid, caller,
+                    mCb.notifyMediaButtonFromController(packageName, pid, uid, caller,
                             createMediaButtonIntent(keyEvent));
                 }
                 return true;
-            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
             }
             return false;
         }
 
         public void sendCommand(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
+                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
             try {
-                mCb.onCommand(packageName, pid, uid, caller, command, args, cb);
-            } catch (RemoteException e) {
+                mCb.notifyCommand(packageName, pid, uid, caller, command, args, cb);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in sendCommand.", e);
             }
         }
 
         public void sendCustomAction(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String action,
+                ControllerCallbackLink caller, String action,
                 Bundle args) {
             try {
-                mCb.onCustomAction(packageName, pid, uid, caller, action, args);
-            } catch (RemoteException e) {
+                mCb.notifyCustomAction(packageName, pid, uid, caller, action, args);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in sendCustomAction.", e);
             }
         }
 
         public void prepare(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             try {
-                mCb.onPrepare(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyPrepare(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in prepare.", e);
             }
         }
 
         public void prepareFromMediaId(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String mediaId, Bundle extras) {
+                ControllerCallbackLink caller, String mediaId, Bundle extras) {
             try {
-                mCb.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
-            } catch (RemoteException e) {
+                mCb.notifyPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
             }
         }
 
         public void prepareFromSearch(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String query, Bundle extras) {
+                ControllerCallbackLink caller, String query, Bundle extras) {
             try {
-                mCb.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
-            } catch (RemoteException e) {
+                mCb.notifyPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
             }
         }
 
         public void prepareFromUri(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Uri uri, Bundle extras) {
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
             try {
-                mCb.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
-            } catch (RemoteException e) {
+                mCb.notifyPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in prepareFromUri.", e);
             }
         }
 
-        public void play(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+        public void play(String packageName, int pid, int uid, ControllerCallbackLink caller) {
             try {
-                mCb.onPlay(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyPlay(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in play.", e);
             }
         }
 
         public void playFromMediaId(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String mediaId, Bundle extras) {
+                ControllerCallbackLink caller, String mediaId, Bundle extras) {
             try {
-                mCb.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
-            } catch (RemoteException e) {
+                mCb.notifyPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in playFromMediaId.", e);
             }
         }
 
         public void playFromSearch(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String query, Bundle extras) {
+                ControllerCallbackLink caller, String query, Bundle extras) {
             try {
-                mCb.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
-            } catch (RemoteException e) {
+                mCb.notifyPlayFromSearch(packageName, pid, uid, caller, query, extras);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in playFromSearch.", e);
             }
         }
 
         public void playFromUri(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Uri uri, Bundle extras) {
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
             try {
-                mCb.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
-            } catch (RemoteException e) {
+                mCb.notifyPlayFromUri(packageName, pid, uid, caller, uri, extras);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in playFromUri.", e);
             }
         }
 
         public void skipToTrack(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, long id) {
+                ControllerCallbackLink caller, long id) {
             try {
-                mCb.onSkipToTrack(packageName, pid, uid, caller, id);
-            } catch (RemoteException e) {
+                mCb.notifySkipToTrack(packageName, pid, uid, caller, id);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in skipToTrack", e);
             }
         }
 
-        public void pause(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+        public void pause(String packageName, int pid, int uid, ControllerCallbackLink caller) {
             try {
-                mCb.onPause(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyPause(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in pause.", e);
             }
         }
 
-        public void stop(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+        public void stop(String packageName, int pid, int uid, ControllerCallbackLink caller) {
             try {
-                mCb.onStop(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyStop(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in stop.", e);
             }
         }
 
-        public void next(String packageName, int pid, int uid, ISessionControllerCallback caller) {
+        public void next(String packageName, int pid, int uid, ControllerCallbackLink caller) {
             try {
-                mCb.onNext(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyNext(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in next.", e);
             }
         }
 
         public void previous(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             try {
-                mCb.onPrevious(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyPrevious(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in previous.", e);
             }
         }
 
         public void fastForward(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             try {
-                mCb.onFastForward(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyFastForward(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in fastForward.", e);
             }
         }
 
         public void rewind(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
+                ControllerCallbackLink caller) {
             try {
-                mCb.onRewind(packageName, pid, uid, caller);
-            } catch (RemoteException e) {
+                mCb.notifyRewind(packageName, pid, uid, caller);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in rewind.", e);
             }
         }
 
-        public void seekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+        public void seekTo(String packageName, int pid, int uid, ControllerCallbackLink caller,
                 long pos) {
             try {
-                mCb.onSeekTo(packageName, pid, uid, caller, pos);
-            } catch (RemoteException e) {
+                mCb.notifySeekTo(packageName, pid, uid, caller, pos);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in seekTo.", e);
             }
         }
 
-        public void rate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+        public void rate(String packageName, int pid, int uid, ControllerCallbackLink caller,
                 Rating rating) {
             try {
-                mCb.onRate(packageName, pid, uid, caller, rating);
-            } catch (RemoteException e) {
+                mCb.notifyRate(packageName, pid, uid, caller, rating);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in rate.", e);
             }
         }
 
         public void adjustVolume(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, boolean asSystemService, int direction) {
+                ControllerCallbackLink caller, boolean asSystemService, int direction) {
             try {
                 if (asSystemService) {
-                    mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
+                    mCb.notifyAdjustVolume(mContext.getPackageName(), Process.myPid(),
                             Process.SYSTEM_UID, null, direction);
                 } else {
-                    mCb.onAdjustVolume(packageName, pid, uid, caller, direction);
+                    mCb.notifyAdjustVolume(packageName, pid, uid, caller, direction);
                 }
-            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in adjustVolume.", e);
             }
         }
 
         public void setVolumeTo(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, int value) {
+                ControllerCallbackLink caller, int value) {
             try {
-                mCb.onSetVolumeTo(packageName, pid, uid, caller, value);
-            } catch (RemoteException e) {
+                mCb.notifySetVolumeTo(packageName, pid, uid, caller, value);
+            } catch (RuntimeException e) {
                 Slog.e(TAG, "Remote failure in setVolumeTo.", e);
             }
         }
@@ -1161,34 +1184,34 @@
 
     class ControllerStub extends ISessionController.Stub {
         @Override
-        public void sendCommand(String packageName, ISessionControllerCallback caller,
+        public void sendCommand(String packageName, ControllerCallbackLink caller,
                 String command, Bundle args, ResultReceiver cb) {
             mSessionCb.sendCommand(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller, command, args, cb);
         }
 
         @Override
-        public boolean sendMediaButton(String packageName, ISessionControllerCallback cb,
+        public boolean sendMediaButton(String packageName, ControllerCallbackLink cb,
                 boolean asSystemService, KeyEvent keyEvent) {
             return mSessionCb.sendMediaButton(packageName, Binder.getCallingPid(),
                     Binder.getCallingUid(), cb, asSystemService, keyEvent);
         }
 
         @Override
-        public void registerCallbackListener(String packageName, ISessionControllerCallback cb) {
+        public void registerCallbackListener(String packageName, ControllerCallbackLink cb) {
             synchronized (mLock) {
                 // If this session is already destroyed tell the caller and
                 // don't add them.
                 if (mDestroyed) {
                     try {
-                        cb.onSessionDestroyed();
+                        cb.notifySessionDestroyed();
                     } catch (Exception e) {
                         // ignored
                     }
                     return;
                 }
                 if (getControllerHolderIndexForCb(cb) < 0) {
-                    mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb,
+                    mControllerCallbackHolders.add(new ControllerCallbackLinkHolder(cb,
                             packageName, Binder.getCallingUid()));
                     if (DEBUG) {
                         Log.d(TAG, "registering controller callback " + cb + " from controller"
@@ -1199,14 +1222,14 @@
         }
 
         @Override
-        public void unregisterCallbackListener(ISessionControllerCallback cb) {
+        public void unregisterCallbackListener(ControllerCallbackLink cb) {
             synchronized (mLock) {
                 int index = getControllerHolderIndexForCb(cb);
                 if (index != -1) {
                     mControllerCallbackHolders.remove(index);
                 }
                 if (DEBUG) {
-                    Log.d(TAG, "unregistering callback " + cb.asBinder());
+                    Log.d(TAG, "unregistering callback " + cb.getBinder());
                 }
             }
         }
@@ -1253,7 +1276,7 @@
 
         @Override
         public void adjustVolume(String packageName, String opPackageName,
-                ISessionControllerCallback caller, boolean asSystemService, int direction,
+                ControllerCallbackLink caller, boolean asSystemService, int direction,
                 int flags) {
             int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
@@ -1268,7 +1291,7 @@
 
         @Override
         public void setVolumeTo(String packageName, String opPackageName,
-                ISessionControllerCallback caller, int value, int flags) {
+                ControllerCallbackLink caller, int value, int flags) {
             int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
@@ -1281,110 +1304,110 @@
         }
 
         @Override
-        public void prepare(String packageName, ISessionControllerCallback caller) {
+        public void prepare(String packageName, ControllerCallbackLink caller) {
             mSessionCb.prepare(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+        public void prepareFromMediaId(String packageName, ControllerCallbackLink caller,
                 String mediaId, Bundle extras) {
             mSessionCb.prepareFromMediaId(packageName, Binder.getCallingPid(),
                     Binder.getCallingUid(), caller, mediaId, extras);
         }
 
         @Override
-        public void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+        public void prepareFromSearch(String packageName, ControllerCallbackLink caller,
                 String query, Bundle extras) {
             mSessionCb.prepareFromSearch(packageName, Binder.getCallingPid(),
                     Binder.getCallingUid(), caller, query, extras);
         }
 
         @Override
-        public void prepareFromUri(String packageName, ISessionControllerCallback caller,
+        public void prepareFromUri(String packageName, ControllerCallbackLink caller,
                 Uri uri, Bundle extras) {
             mSessionCb.prepareFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller, uri, extras);
         }
 
         @Override
-        public void play(String packageName, ISessionControllerCallback caller) {
+        public void play(String packageName, ControllerCallbackLink caller) {
             mSessionCb.play(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void playFromMediaId(String packageName, ISessionControllerCallback caller,
+        public void playFromMediaId(String packageName, ControllerCallbackLink caller,
                 String mediaId, Bundle extras) {
             mSessionCb.playFromMediaId(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller, mediaId, extras);
         }
 
         @Override
-        public void playFromSearch(String packageName, ISessionControllerCallback caller,
+        public void playFromSearch(String packageName, ControllerCallbackLink caller,
                 String query, Bundle extras) {
             mSessionCb.playFromSearch(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller, query, extras);
         }
 
         @Override
-        public void playFromUri(String packageName, ISessionControllerCallback caller,
+        public void playFromUri(String packageName, ControllerCallbackLink caller,
                 Uri uri, Bundle extras) {
             mSessionCb.playFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller, uri, extras);
         }
 
         @Override
-        public void skipToQueueItem(String packageName, ISessionControllerCallback caller,
+        public void skipToQueueItem(String packageName, ControllerCallbackLink caller,
                 long id) {
             mSessionCb.skipToTrack(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller, id);
         }
 
         @Override
-        public void pause(String packageName, ISessionControllerCallback caller) {
+        public void pause(String packageName, ControllerCallbackLink caller) {
             mSessionCb.pause(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void stop(String packageName, ISessionControllerCallback caller) {
+        public void stop(String packageName, ControllerCallbackLink caller) {
             mSessionCb.stop(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void next(String packageName, ISessionControllerCallback caller) {
+        public void next(String packageName, ControllerCallbackLink caller) {
             mSessionCb.next(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void previous(String packageName, ISessionControllerCallback caller) {
+        public void previous(String packageName, ControllerCallbackLink caller) {
             mSessionCb.previous(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller);
         }
 
         @Override
-        public void fastForward(String packageName, ISessionControllerCallback caller) {
+        public void fastForward(String packageName, ControllerCallbackLink caller) {
             mSessionCb.fastForward(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller);
         }
 
         @Override
-        public void rewind(String packageName, ISessionControllerCallback caller) {
+        public void rewind(String packageName, ControllerCallbackLink caller) {
             mSessionCb.rewind(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void seekTo(String packageName, ISessionControllerCallback caller, long pos) {
+        public void seekTo(String packageName, ControllerCallbackLink caller, long pos) {
             mSessionCb.seekTo(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
                     pos);
         }
 
         @Override
-        public void rate(String packageName, ISessionControllerCallback caller, Rating rating) {
+        public void rate(String packageName, ControllerCallbackLink caller, Rating rating) {
             mSessionCb.rate(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
                     rating);
         }
 
         @Override
-        public void sendCustomAction(String packageName, ISessionControllerCallback caller,
+        public void sendCustomAction(String packageName, ControllerCallbackLink caller,
                 String action, Bundle args) {
             mSessionCb.sendCustomAction(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
                     caller, action, args);
@@ -1403,7 +1426,7 @@
         }
 
         @Override
-        public ParceledListSlice getQueue() {
+        public List<QueueItem> getQueue() {
             synchronized (mLock) {
                 return mQueue;
             }
@@ -1432,12 +1455,12 @@
         }
     }
 
-    private class ISessionControllerCallbackHolder {
-        private final ISessionControllerCallback mCallback;
+    private class ControllerCallbackLinkHolder {
+        private final ControllerCallbackLink mCallback;
         private final String mPackageName;
         private final int mUid;
 
-        ISessionControllerCallbackHolder(ISessionControllerCallback callback, String packageName,
+        ControllerCallbackLinkHolder(ControllerCallbackLink callback, String packageName,
                 int uid) {
             mCallback = callback;
             mPackageName = packageName;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 7f2e047..ba7b87e 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.media;
 
+import static android.os.UserHandle.USER_ALL;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.INotificationManager;
@@ -48,10 +50,11 @@
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
 import android.media.session.ISession;
-import android.media.session.ISessionCallback;
+import android.media.session.ISession2TokensListener;
 import android.media.session.ISessionManager;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
+import android.media.session.SessionCallbackLink;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -114,10 +117,14 @@
     @GuardedBy("mLock")
     private final ArrayList<SessionsListenerRecord> mSessionsListeners
             = new ArrayList<SessionsListenerRecord>();
+    // Map user id as index to list of Session2Tokens
     // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
     //       one place.
     @GuardedBy("mLock")
-    private final List<Session2Token> mSession2Tokens = new ArrayList<>();
+    private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
+            new ArrayList<>();
 
     private KeyguardManager mKeyguardManager;
     private IAudioService mAudioService;
@@ -234,7 +241,7 @@
 
     private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
         List<MediaSessionRecord> records = new ArrayList<>();
-        if (userId == UserHandle.USER_ALL) {
+        if (userId == USER_ALL) {
             int size = mUserRecords.size();
             for (int i = 0; i < size; i++) {
                 records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
@@ -250,13 +257,24 @@
 
         // Return global priority session at the first whenever it's asked.
         if (isGlobalPriorityActiveLocked()
-                && (userId == UserHandle.USER_ALL
-                    || userId == mGlobalPrioritySession.getUserId())) {
+                && (userId == USER_ALL || userId == mGlobalPrioritySession.getUserId())) {
             records.add(0, mGlobalPrioritySession);
         }
         return records;
     }
 
+    List<Session2Token> getSession2TokensLocked(int userId) {
+        List<Session2Token> list = new ArrayList<>();
+        if (userId == USER_ALL) {
+            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+                list.addAll(mSession2TokensPerUser.valueAt(i));
+            }
+        } else {
+            list.addAll(mSession2TokensPerUser.get(userId));
+        }
+        return list;
+    }
+
     /**
      * Tells the system UI that volume has changed on an active remote session.
      */
@@ -305,19 +323,23 @@
         updateUser();
     }
 
+    // Called when the user with the userId is removed.
     @Override
     public void onStopUser(int userId) {
         if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
         synchronized (mLock) {
+            // TODO: Also handle removing user in updateUser() because adding/switching user is
+            //       handled in updateUser().
             FullUserRecord user = getFullUserRecordLocked(userId);
             if (user != null) {
                 if (user.mFullUserId == userId) {
-                    user.destroySessionsForUserLocked(UserHandle.USER_ALL);
+                    user.destroySessionsForUserLocked(USER_ALL);
                     mUserRecords.remove(userId);
                 } else {
                     user.destroySessionsForUserLocked(userId);
                 }
             }
+            mSession2TokensPerUser.remove(userId);
             updateUser();
         }
     }
@@ -363,6 +385,9 @@
                             mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
                         }
                     }
+                    if (mSession2TokensPerUser.get(userInfo.id) == null) {
+                        mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
+                    }
                 }
             }
             // Ensure that the current full user exists.
@@ -372,6 +397,9 @@
                 Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
                 mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
                 mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
+                if (mSession2TokensPerUser.get(currentFullUserId) == null) {
+                    mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
+                }
             }
             mFullUserIds.put(currentFullUserId, currentFullUserId);
         }
@@ -382,14 +410,14 @@
             for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
                 SessionsListenerRecord listener = mSessionsListeners.get(i);
                 try {
-                    enforceMediaPermissions(listener.mComponentName, listener.mPid, listener.mUid,
-                            listener.mUserId);
+                    enforceMediaPermissions(listener.componentName, listener.pid, listener.uid,
+                            listener.userId);
                 } catch (SecurityException e) {
-                    Log.i(TAG, "ActiveSessionsListener " + listener.mComponentName
+                    Log.i(TAG, "ActiveSessionsListener " + listener.componentName
                             + " is no longer authorized. Disconnecting.");
                     mSessionsListeners.remove(i);
                     try {
-                        listener.mListener
+                        listener.listener
                                 .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
                     } catch (Exception e1) {
                         // ignore
@@ -425,7 +453,7 @@
         }
 
         try {
-            session.getCallback().asBinder().unlinkToDeath(session, 0);
+            session.getCallback().getBinder().unlinkToDeath(session, 0);
         } catch (Exception e) {
             // ignore exceptions while destroying a session.
         }
@@ -511,7 +539,7 @@
     }
 
     private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
-            String callerPackageName, ISessionCallback cb, String tag) throws RemoteException {
+            String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
         synchronized (mLock) {
             return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
         }
@@ -525,7 +553,7 @@
      * 4. It needs to be added to the relevant user record.
      */
     private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
-            String callerPackageName, ISessionCallback cb, String tag) {
+            String callerPackageName, SessionCallbackLink cb, String tag) {
         FullUserRecord user = getFullUserRecordLocked(userId);
         if (user == null) {
             Log.wtf(TAG, "Request from invalid user: " +  userId);
@@ -535,7 +563,7 @@
         final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
                 callerPackageName, cb, tag, this, mHandler.getLooper());
         try {
-            cb.asBinder().linkToDeath(session, 0);
+            cb.getBinder().linkToDeath(session, 0);
         } catch (RemoteException e) {
             throw new RuntimeException("Media Session owner died prematurely.", e);
         }
@@ -551,13 +579,23 @@
 
     private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
         for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
-            if (mSessionsListeners.get(i).mListener.asBinder() == listener.asBinder()) {
+            if (mSessionsListeners.get(i).listener.asBinder() == listener.asBinder()) {
                 return i;
             }
         }
         return -1;
     }
 
+    private int findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener) {
+        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+            if (mSession2TokensListenerRecords.get(i).listener.asBinder() == listener.asBinder()) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+
     private void pushSessionsChanged(int userId) {
         synchronized (mLock) {
             FullUserRecord user = getFullUserRecordLocked(userId);
@@ -574,9 +612,9 @@
             pushRemoteVolumeUpdateLocked(userId);
             for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
                 SessionsListenerRecord record = mSessionsListeners.get(i);
-                if (record.mUserId == UserHandle.USER_ALL || record.mUserId == userId) {
+                if (record.userId == USER_ALL || record.userId == userId) {
                     try {
-                        record.mListener.onActiveSessionsChanged(tokens);
+                        record.listener.onActiveSessionsChanged(tokens);
                     } catch (RemoteException e) {
                         Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
                                 e);
@@ -603,6 +641,25 @@
         }
     }
 
+    void pushSession2TokensChangedLocked(int userId) {
+        List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
+        List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
+
+        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+            Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
+            try {
+                if (listenerRecord.userId == USER_ALL) {
+                    listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
+                } else if (listenerRecord.userId == userId) {
+                    listenerRecord.listener.onSession2TokensChanged(session2Tokens);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
+                mSession2TokensListenerRecords.remove(i);
+            }
+        }
+    }
+
     /**
      * Called when the media button receiver for the {@param record} is changed.
      *
@@ -732,9 +789,15 @@
             pw.println(indent + "Restored MediaButtonReceiverComponentType: "
                     + mRestoredMediaButtonReceiverComponentType);
             mPriorityStack.dump(pw, indent);
-            pw.println(indent + "Session2Tokens - " + mSession2Tokens.size());
-            for (Session2Token session2Token : mSession2Tokens) {
-                pw.println(indent + "  " + session2Token);
+            pw.println(indent + "Session2Tokens:");
+            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+                List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
+                if (list == null || list.size() == 0) {
+                    continue;
+                }
+                for (Session2Token token : list) {
+                    pw.println(indent + "  " + token);
+                }
             }
         }
 
@@ -838,20 +901,20 @@
     }
 
     final class SessionsListenerRecord implements IBinder.DeathRecipient {
-        private final IActiveSessionsListener mListener;
-        private final ComponentName mComponentName;
-        private final int mUserId;
-        private final int mPid;
-        private final int mUid;
+        public final IActiveSessionsListener listener;
+        public final ComponentName componentName;
+        public final int userId;
+        public final int pid;
+        public final int uid;
 
         public SessionsListenerRecord(IActiveSessionsListener listener,
                 ComponentName componentName,
                 int userId, int pid, int uid) {
-            mListener = listener;
-            mComponentName = componentName;
-            mUserId = userId;
-            mPid = pid;
-            mUid = uid;
+            this.listener = listener;
+            this.componentName = componentName;
+            this.userId = userId;
+            this.pid = pid;
+            this.uid = uid;
         }
 
         @Override
@@ -862,6 +925,24 @@
         }
     }
 
+    final class Session2TokensListenerRecord implements IBinder.DeathRecipient {
+        public final ISession2TokensListener listener;
+        public final int userId;
+
+        Session2TokensListenerRecord(ISession2TokensListener listener,
+                int userId) {
+            this.listener = listener;
+            this.userId = userId;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mSession2TokensListenerRecords.remove(this);
+            }
+        }
+    }
+
     final class SettingsObserver extends ContentObserver {
         private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
                 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
@@ -872,7 +953,7 @@
 
         private void observe() {
             mContentResolver.registerContentObserver(mSecureSettingsUri,
-                    false, this, UserHandle.USER_ALL);
+                    false, this, USER_ALL);
         }
 
         @Override
@@ -890,7 +971,7 @@
         private boolean mVoiceButtonHandled = false;
 
         @Override
-        public ISession createSession(String packageName, ISessionCallback cb, String tag,
+        public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
                 int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
@@ -956,6 +1037,28 @@
         }
 
         @Override
+        public List<Session2Token> getSession2Tokens(int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                // Check that they can make calls on behalf of the user and
+                // get the final user id
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        true /* allowAll */, true /* requireFull */, "getSession2Tokens",
+                        null /* optional packageName */);
+                List<Session2Token> result;
+                synchronized (mLock) {
+                    result = getSession2TokensLocked(resolvedUserId);
+                }
+                return result;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public void addSessionsListener(IActiveSessionsListener listener,
                 ComponentName componentName, int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
@@ -993,7 +1096,7 @@
                 if (index != -1) {
                     SessionsListenerRecord record = mSessionsListeners.remove(index);
                     try {
-                        record.mListener.asBinder().unlinkToDeath(record, 0);
+                        record.listener.asBinder().unlinkToDeath(record, 0);
                     } catch (Exception e) {
                         // ignore exceptions, the record is being removed
                     }
@@ -1001,6 +1104,56 @@
             }
         }
 
+        @Override
+        public void addSession2TokensListener(ISession2TokensListener listener,
+                int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                // Check that they can make calls on behalf of the user and get the final user id.
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
+                        null /* optional packageName */);
+                synchronized (mLock) {
+                    int index = findIndexOfSession2TokensListenerLocked(listener);
+                    if (index >= 0) {
+                        Log.w(TAG, "addSession2TokensListener is already added, ignoring");
+                        return;
+                    }
+                    mSession2TokensListenerRecords.add(
+                            new Session2TokensListenerRecord(listener, resolvedUserId));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void removeSession2TokensListener(ISession2TokensListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                synchronized (mLock) {
+                    int index = findIndexOfSession2TokensListenerLocked(listener);
+                    if (index >= 0) {
+                        Session2TokensListenerRecord listenerRecord =
+                                mSession2TokensListenerRecords.remove(index);
+                        try {
+                            listenerRecord.listener.asBinder().unlinkToDeath(listenerRecord, 0);
+                        } catch (Exception e) {
+                            // Ignore exception.
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         /**
          * Handles the dispatching of the media button events to one of the
          * registered listeners, or if there was none, broadcast an
@@ -1965,14 +2118,18 @@
         @Override
         public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
             synchronized (mLock) {
-                mSession2Tokens.add(mToken);
+                int userId = UserHandle.getUserId(mToken.getUid());
+                mSession2TokensPerUser.get(userId).add(mToken);
+                pushSession2TokensChangedLocked(userId);
             }
         }
 
         @Override
         public void onDisconnected(MediaController2 controller) {
             synchronized (mLock) {
-                mSession2Tokens.remove(mToken);
+                int userId = UserHandle.getUserId(mToken.getUid());
+                mSession2TokensPerUser.get(userId).remove(mToken);
+                pushSession2TokensChangedLocked(userId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c68e0f9..7b7a3ec 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -77,6 +77,7 @@
 
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
+import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
@@ -1580,6 +1581,9 @@
 
         mIsAutomotive =
                 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
+
+        mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
+                com.android.internal.R.array.config_nonBlockableNotificationPackages));
     }
 
     @Override
@@ -4452,7 +4456,8 @@
                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
                                 WHITELIST_TOKEN, duration);
                         am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
-                                WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER));
+                                WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
+                                        | FLAG_SERVICE_SENDER));
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 9942f59..5598741 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -91,7 +91,6 @@
 public final class NotificationRecord {
     static final String TAG = "NotificationRecord";
     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final int MAX_LOGTAG_LENGTH = 35;
     // the period after which a notification is updated where it can make sound
     private static final int MAX_SOUND_DELAY_MS = 2000;
     final StatusBarNotification sbn;
@@ -162,10 +161,7 @@
     private ArrayList<String> mPeopleOverride;
     private ArrayList<SnoozeCriterion> mSnoozeCriteria;
     private boolean mShowBadge;
-    private LogMaker mLogMaker;
     private Light mLight;
-    private String mGroupLogTag;
-    private String mChannelIdLogTag;
     /**
      * This list contains system generated smart actions from NAS, app-generated smart actions are
      * stored in Notification.actions with isContextual() set to true.
@@ -789,7 +785,8 @@
             mImportanceExplanation = "user";
         }
         if (!getChannel().hasUserSetImportance()
-                && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
+                && mAssistantImportance != IMPORTANCE_UNSPECIFIED
+                && !getChannel().isImportanceLockedByOEM()) {
             mImportance = mAssistantImportance;
             mImportanceExplanation = "asst";
         }
@@ -969,33 +966,6 @@
 
     public void setOverrideGroupKey(String overrideGroupKey) {
         sbn.setOverrideGroupKey(overrideGroupKey);
-        mGroupLogTag = null;
-    }
-
-    private String getGroupLogTag() {
-        if (mGroupLogTag == null) {
-            mGroupLogTag = shortenTag(sbn.getGroup());
-        }
-        return mGroupLogTag;
-    }
-
-    private String getChannelIdLogTag() {
-        if (mChannelIdLogTag == null) {
-            mChannelIdLogTag = shortenTag(mChannel.getId());
-        }
-        return mChannelIdLogTag;
-    }
-
-    private String shortenTag(String longTag) {
-        if (longTag == null) {
-            return null;
-        }
-        if (longTag.length() < MAX_LOGTAG_LENGTH) {
-            return longTag;
-        } else {
-            return longTag.substring(0, MAX_LOGTAG_LENGTH - 8) + "-" +
-                    Integer.toHexString(longTag.hashCode());
-        }
     }
 
     public NotificationChannel getChannel() {
@@ -1272,24 +1242,9 @@
     }
 
     public LogMaker getLogMaker(long now) {
-        if (mLogMaker == null) {
-            // initialize fields that only change on update (so a new record)
-            mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
-                    .setPackageName(sbn.getPackageName())
-                    .addTaggedData(MetricsEvent.NOTIFICATION_ID, sbn.getId())
-                    .addTaggedData(MetricsEvent.NOTIFICATION_TAG, sbn.getTag())
-                    .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
-        }
-        // reset fields that can change between updates, or are used by multiple logs
-        return mLogMaker
-                .clearCategory()
-                .clearType()
-                .clearSubtype()
+        return sbn.getLogMaker()
                 .clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX)
                 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
-                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
-                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
-                        sbn.getNotification().isGroupSummary() ? 1 : 0)
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7c0e0b0..28f6972 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -68,6 +68,7 @@
     private static final String TAG = "NotificationPrefHelper";
     private static final int XML_VERSION = 1;
     private static final int UNKNOWN_UID = UserHandle.USER_NULL;
+    private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
 
     @VisibleForTesting
     static final String TAG_RANKING = "ranking";
@@ -94,6 +95,7 @@
     private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_SHOW_BADGE = true;
     private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+    private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE  = false;
     /**
      * Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
      * fields.
@@ -621,6 +623,12 @@
             channel.setLockscreenVisibility(r.visibility);
         }
         clearLockedFields(channel);
+        channel.setImportanceLockedByOEM(r.oemLockedImportance);
+        if (!channel.isImportanceLockedByOEM()) {
+            if (r.futureOemLockedChannels.remove(channel.getId())) {
+                channel.setImportanceLockedByOEM(true);
+            }
+        }
         if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
             channel.setLockscreenVisibility(
                     NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
@@ -664,6 +672,12 @@
         } else {
             updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
         }
+        // no importance updates are allowed if OEM blocked it
+        updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM());
+        if (updatedChannel.isImportanceLockedByOEM()) {
+            updatedChannel.setImportance(channel.getImportance());
+        }
+
         r.channels.put(updatedChannel.getId(), updatedChannel);
 
         if (onlyHasDefaultChannel(pkg, uid)) {
@@ -753,6 +767,44 @@
         }
     }
 
+    public void lockChannelsForOEM(String[] appOrChannelList) {
+        if (appOrChannelList == null) {
+            return;
+        }
+        for (String appOrChannel : appOrChannelList) {
+            if (!TextUtils.isEmpty(appOrChannel)) {
+                String[] appSplit = appOrChannel.split(NON_BLOCKABLE_CHANNEL_DELIM);
+                if (appSplit != null && appSplit.length > 0) {
+                    String appName = appSplit[0];
+                    String channelId = appSplit.length == 2 ? appSplit[1] : null;
+
+                    synchronized (mPackagePreferences) {
+                        for (PackagePreferences r : mPackagePreferences.values()) {
+                            if (r.pkg.equals(appName)) {
+                                if (channelId == null) {
+                                    // lock all channels for the app
+                                    r.oemLockedImportance = true;
+                                    for (NotificationChannel channel : r.channels.values()) {
+                                        channel.setImportanceLockedByOEM(true);
+                                    }
+                                } else {
+                                    NotificationChannel channel = r.channels.get(channelId);
+                                    if (channel != null) {
+                                        channel.setImportanceLockedByOEM(true);
+                                    } else {
+                                        // if this channel shows up in the future, make sure it'll
+                                        // be locked immediately
+                                        r.futureOemLockedChannels.add(channelId);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
             int uid, String groupId, boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
@@ -1604,6 +1656,8 @@
         boolean showBadge = DEFAULT_SHOW_BADGE;
         boolean appOverlay = DEFAULT_ALLOW_APP_OVERLAY;
         int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+        boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
+        List<String> futureOemLockedChannels = new ArrayList<>();
 
         Delegate delegate = null;
         ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/os/BugreportManagerService.java b/services/core/java/com/android/server/os/BugreportManagerService.java
new file mode 100644
index 0000000..e241591
--- /dev/null
+++ b/services/core/java/com/android/server/os/BugreportManagerService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+/**
+ * Service that provides a privileged API to capture and consume bugreports.
+ *
+ * @hide
+ */
+public class BugreportManagerService extends SystemService {
+    private static final String TAG = "BugreportManagerService";
+
+    private BugreportManagerServiceImpl mService;
+
+    public BugreportManagerService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        mService = new BugreportManagerServiceImpl(getContext());
+        // TODO(b/111441001): Needs sepolicy to be submitted first.
+        // publishBinderService(Context.BUGREPORT_SERVICE, mService);
+    }
+}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
new file mode 100644
index 0000000..faa4714
--- /dev/null
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.BugreportParams;
+import android.os.IDumpstate;
+import android.os.IDumpstateListener;
+import android.os.IDumpstateToken;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+
+// TODO(b/111441001):
+// 1. Handle the case where another bugreport is in progress
+// 2. Make everything threadsafe
+// 3. Pass validation & other errors on listener
+
+/**
+ * Implementation of the service that provides a privileged API to capture and consume bugreports.
+ *
+ * <p>Delegates the actualy generation to a native implementation of {@code Dumpstate}.
+ */
+class BugreportManagerServiceImpl extends IDumpstate.Stub {
+    private static final String TAG = "BugreportManagerService";
+    private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
+
+    private IDumpstate mDs = null;
+    private final Context mContext;
+
+    BugreportManagerServiceImpl(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public IDumpstateToken setListener(String name, IDumpstateListener listener,
+            boolean getSectionDetails) throws RemoteException {
+        // TODO(b/111441001): Figure out if lazy setting of listener should be allowed
+        // and if so how to handle it.
+        throw new UnsupportedOperationException("setListener is not allowed on this service");
+    }
+
+
+    @Override
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void startBugreport(FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+            int bugreportMode, IDumpstateListener listener) throws RemoteException {
+
+        validate(bugreportMode);
+
+        mDs = getDumpstateService();
+        if (mDs == null) {
+            Slog.w(TAG, "Unable to get bugreport service");
+            // TODO(b/111441001): pass error on listener
+            return;
+        }
+        mDs.startBugreport(bugreportFd, screenshotFd, bugreportMode, listener);
+    }
+
+    private boolean validate(@BugreportParams.BugreportMode int mode) {
+        if (mode != BugreportParams.BUGREPORT_MODE_FULL
+                && mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE
+                && mode != BugreportParams.BUGREPORT_MODE_REMOTE
+                && mode != BugreportParams.BUGREPORT_MODE_WEAR
+                && mode != BugreportParams.BUGREPORT_MODE_TELEPHONY
+                && mode != BugreportParams.BUGREPORT_MODE_WIFI) {
+            Slog.w(TAG, "Unknown bugreport mode: " + mode);
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Start and get a handle to the native implementation of {@code IDumpstate} which does the
+     * actual bugreport generation.
+     *
+     * <p>Generating bugreports requires root privileges. To limit the footprint
+     * of the root access, the actual generation in Dumpstate binary is accessed as a
+     * oneshot service 'bugreport'.
+     */
+    private IDumpstate getDumpstateService() {
+        // Start bugreport service.
+        SystemProperties.set("ctl.start", "bugreport");
+
+        IDumpstate ds = null;
+        boolean timedOut = false;
+        int totalTimeWaitedMillis = 0;
+        int seedWaitTimeMillis = 500;
+        while (!timedOut) {
+            // Note that the binder service on the native side is "dumpstate".
+            ds = IDumpstate.Stub.asInterface(ServiceManager.getService("dumpstate"));
+            if (ds != null) {
+                Slog.i(TAG, "Got bugreport service handle.");
+                break;
+            }
+            SystemClock.sleep(seedWaitTimeMillis);
+            Slog.i(TAG,
+                    "Waiting to get dumpstate service handle (" + totalTimeWaitedMillis + "ms)");
+            totalTimeWaitedMillis += seedWaitTimeMillis;
+            seedWaitTimeMillis *= 2;
+            timedOut = totalTimeWaitedMillis > DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS;
+        }
+        if (timedOut) {
+            Slog.w(TAG,
+                    "Timed out waiting to get dumpstate service handle ("
+                    + totalTimeWaitedMillis + "ms)");
+        }
+        return ds;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 3b11525..8facce1 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -42,6 +42,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.Pair;
@@ -60,6 +61,7 @@
 
 /** Resolves all Android component types [activities, services, providers and receivers]. */
 public class ComponentResolver {
+    private static final boolean DEBUG = false;
     private static final String TAG = "PackageManager";
     private static final boolean DEBUG_FILTERS = false;
     private static final boolean DEBUG_SHOW_INFO = false;
@@ -1198,22 +1200,48 @@
             return packageName.equals(info.activity.owner.packageName);
         }
 
+        private void log(String reason, ActivityIntentInfo info, int match,
+                int userId) {
+            Slog.w(TAG, reason
+                    + "; match: "
+                    + DebugUtils.flagsToString(IntentFilter.class, "MATCH_", match)
+                    + "; userId: " + userId
+                    + "; intent info: " + info);
+        }
+
         @Override
         protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
                 int match, int userId) {
-            if (!sUserManager.exists(userId)) return null;
+            if (!sUserManager.exists(userId)) {
+                if (DEBUG) {
+                    log("User doesn't exist", info, match, userId);
+                }
+                return null;
+            }
             if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) {
+                if (DEBUG) {
+                    log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
+                            + DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags),
+                            info, match, userId);
+                }
                 return null;
             }
             final PackageParser.Activity activity = info.activity;
             PackageSetting ps = (PackageSetting) activity.owner.mExtras;
             if (ps == null) {
+                if (DEBUG) {
+                    log("info.activity.owner.mExtras == null", info, match, userId);
+                }
                 return null;
             }
             final PackageUserState userState = ps.readUserState(userId);
             ActivityInfo ai =
                     PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
             if (ai == null) {
+                if (DEBUG) {
+                    log("Failed to create ActivityInfo based on " + info.activity, info, match,
+                            userId);
+                }
                 return null;
             }
             final boolean matchExplicitlyVisibleOnly =
@@ -1227,15 +1255,31 @@
             final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
             // throw out filters that aren't visible to ephemeral apps
             if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) {
+                if (DEBUG) {
+                    log("Filter(s) not visible to ephemeral apps"
+                            + "; matchVisibleToInstantApp=" + matchVisibleToInstantApp
+                            + "; matchInstantApp=" + matchInstantApp
+                            + "; info.isVisibleToInstantApp()=" + info.isVisibleToInstantApp()
+                            + "; matchExplicitlyVisibleOnly=" + matchExplicitlyVisibleOnly
+                            + "; info.isExplicitlyVisibleToInstantApp()="
+                                    + info.isExplicitlyVisibleToInstantApp(),
+                            info, match, userId);
+                }
                 return null;
             }
             // throw out instant app filters if we're not explicitly requesting them
             if (!matchInstantApp && userState.instantApp) {
+                if (DEBUG) {
+                    log("Instant app filter is not explicitly requested", info, match, userId);
+                }
                 return null;
             }
             // throw out instant app filters if updates are available; will trigger
             // instant app resolution
             if (userState.instantApp && ps.isUpdateAvailable()) {
+                if (DEBUG) {
+                    log("Instant app update is available", info, match, userId);
+                }
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 7f1fb6c..aa9bc26 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -313,6 +313,10 @@
                     Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) {
                 return launcherActivities;
             }
+            if (launcherActivities == null) {
+                // Cannot access profile, so we don't even return any hidden apps.
+                return null;
+            }
 
             final int callingUid = injectBinderCallingUid();
             final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7ca39df..d0b20e8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -329,6 +329,9 @@
 
                         if (valid) {
                             mSessions.put(session.sessionId, session);
+                            if (session.isStaged()) {
+                                mStagingManager.restoreSession(session);
+                            }
                         } else {
                             // Since this is early during boot we don't send
                             // any observer events about the session, but we
@@ -533,7 +536,7 @@
         session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
                 mInstallThread.getLooper(), mStagingManager, sessionId, userId,
                 installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false,
-                false, null, SessionInfo.INVALID_ID);
+                false, null, SessionInfo.INVALID_ID, false, false, false, SessionInfo.NO_ERROR);
 
         synchronized (mSessions) {
             mSessions.put(sessionId, session);
@@ -1131,7 +1134,9 @@
                         }
                     }
                     synchronized (mSessions) {
-                        mSessions.remove(session.sessionId);
+                        if (!session.isStaged() || !success) {
+                            mSessions.remove(session.sessionId);
+                        }
                         addHistoricalSessionLocked(session);
 
                         final File appIconFile = buildAppIconFile(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5cb6c34..516927f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -151,6 +151,10 @@
     private static final String ATTR_MULTI_PACKAGE = "multiPackage";
     private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
     private static final String ATTR_STAGED_SESSION = "stagedSession";
+    private static final String ATTR_IS_READY = "isReady";
+    private static final String ATTR_IS_FAILED = "isFailed";
+    private static final String ATTR_IS_APPLIED = "isApplied";
+    private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
     private static final String ATTR_MODE = "mode";
     private static final String ATTR_INSTALL_FLAGS = "installFlags";
     private static final String ATTR_INSTALL_LOCATION = "installLocation";
@@ -408,7 +412,8 @@
             int sessionId, int userId,
             String installerPackageName, int installerUid, SessionParams params, long createdMillis,
             File stageDir, String stageCid, boolean prepared, boolean sealed,
-            @Nullable int[] childSessionIds, int parentSessionId) {
+            @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
+            boolean isFailed, boolean isApplied, int stagedSessionErrorCode) {
         mCallback = callback;
         mContext = context;
         mPm = pm;
@@ -438,7 +443,10 @@
         }
 
         mPrepared = prepared;
-
+        mStagedSessionReady = isReady;
+        mStagedSessionFailed = isFailed;
+        mStagedSessionApplied = isApplied;
+        mStagedSessionErrorCode = stagedSessionErrorCode;
         if (sealed) {
             synchronized (mLock) {
                 try {
@@ -2023,8 +2031,9 @@
     private void destroyInternal() {
         synchronized (mLock) {
             mSealed = true;
-            mDestroyed = true;
-
+            if (!params.isStaged) {
+                mDestroyed = true;
+            }
             // Force shut down all bridges
             for (RevocableFileDescriptor fd : mFds) {
                 fd.revoke();
@@ -2131,6 +2140,10 @@
 
             writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
             writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
+            writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
+            writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
+            writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
+            writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
             // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
             //                       we've read all sessions.
             writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
@@ -2269,10 +2282,16 @@
             params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
             params.appIconLastModified = appIconFile.lastModified();
         }
+        final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
+        final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
+        final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
+        final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE);
+
         return new PackageInstallerSession(callback, context, pm, sessionProvider,
                 installerThread, stagingManager, sessionId, userId, installerPackageName,
                 installerUid, params, createdMillis, stageDir, stageCid, prepared, sealed,
-                EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
+                EMPTY_CHILD_SESSION_ARRAY, parentSessionId, isReady, isFailed, isApplied,
+                stagedSessionErrorCode);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3301962..597f5b3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13562,7 +13562,8 @@
             }
 
             Signature[] callerSignature;
-            Object obj = mSettings.getSettingLPr(callingUid);
+            final int appId = UserHandle.getAppId(callingUid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     callerSignature =
@@ -16910,19 +16911,29 @@
             final String filePath = entry.getKey();
             final String signaturePath = entry.getValue();
 
-            final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(
-                    filePath, signaturePath, legacyMode);
+            if (!legacyMode) {
+                // fs-verity is optional for now.  Only set up if signature is provided.
+                if (new File(signaturePath).exists()) {
+                    try {
+                        VerityUtils.setUpFsverity(filePath, signaturePath);
+                    } catch (IOException | DigestException | NoSuchAlgorithmException
+                            | SecurityException e) {
+                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+                                "Failed to enable fs-verity: " + e);
+                    }
+                }
+                continue;
+            }
+
+            // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
+            final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
             if (result.isOk()) {
                 if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
                 final FileDescriptor fd = result.getUnownedFileDescriptor();
                 try {
                     mInstaller.installApkVerity(filePath, fd, result.getContentSize());
-
-                    // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
-                    if (legacyMode) {
-                        final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
-                        mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
-                    }
+                    final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
+                    mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
                 } finally {
                     IoUtils.closeQuietly(fd);
                 }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 2329356..c297c62 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.apex.ApexInfo;
+import android.apex.ApexInfoList;
 import android.apex.IApexService;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
@@ -52,9 +53,6 @@
     private final PackageManagerService mPm;
     private final Handler mBgHandler;
 
-    // STOPSHIP: This is a temporary mock implementation of staged sessions. This variable
-    //           shouldn't be needed at all.
-    // TODO(b/118865310): Implement staged sessions logic.
     @GuardedBy("mStagedSessions")
     private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
 
@@ -127,28 +125,55 @@
         return false;
     }
 
-    void commitSession(@NonNull PackageInstallerSession sessionInfo) {
-        updateStoredSession(sessionInfo);
+    private static boolean submitSessionToApexService(int sessionId, ApexInfoList apexInfoList) {
+        final IApexService apex = IApexService.Stub.asInterface(
+                ServiceManager.getService("apexservice"));
+        boolean success;
+        try {
+            success = apex.submitStagedSession(sessionId, apexInfoList);
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact apexservice", re);
+            return false;
+        }
+        return success;
+    }
 
-        mBgHandler.post(() -> {
-            sessionInfo.setStagedSessionReady();
+    void preRebootVerification(@NonNull PackageInstallerSession session) {
+        boolean success = true;
+        if ((session.params.installFlags & PackageManager.INSTALL_APEX) != 0) {
 
-            SessionInfo session = sessionInfo.generateInfo(false);
-            // For APEXes, we validate the signature here before we write the package to the
-            // staging directory. For APKs, the signature verification will be done by the package
-            // manager at the point at which it applies the staged install.
-            //
-            // TODO: Decide whether we want to fail fast by detecting signature mismatches right
-            // away.
-            if ((sessionInfo.params.installFlags & PackageManager.INSTALL_APEX) != 0) {
-                if (!validateApexSignatureLocked(session.resolvedBaseCodePath,
-                        session.appPackageName)) {
-                    sessionInfo.setStagedSessionFailed(SessionInfo.VERIFICATION_FAILED);
+            final ApexInfoList apexInfoList = new ApexInfoList();
+
+            if (!submitSessionToApexService(session.sessionId, apexInfoList)) {
+                success = false;
+            } else {
+                // For APEXes, we validate the signature here before we mark the session as ready,
+                // so we fail the session early if there is a signature mismatch. For APKs, the
+                // signature verification will be done by the package manager at the point at which
+                // it applies the staged install.
+                //
+                // TODO: Decide whether we want to fail fast by detecting signature mismatches right
+                // away.
+                for (ApexInfo apexPackage : apexInfoList.apexInfos) {
+                    if (!validateApexSignatureLocked(apexPackage.packagePath,
+                            apexPackage.packageName)) {
+                        success = false;
+                        break;
+                    }
                 }
             }
+        }
+        if (success) {
+            session.setStagedSessionReady();
+        } else {
+            session.setStagedSessionFailed(SessionInfo.VERIFICATION_FAILED);
+        }
+        mPm.sendSessionUpdatedBroadcast(session.generateInfo(false), session.userId);
+    }
 
-            mPm.sendSessionUpdatedBroadcast(sessionInfo.generateInfo(false), sessionInfo.userId);
-        });
+    void commitSession(@NonNull PackageInstallerSession session) {
+        updateStoredSession(session);
+        mBgHandler.post(() -> preRebootVerification(session));
     }
 
     void createSession(@NonNull PackageInstallerSession sessionInfo) {
@@ -163,4 +188,11 @@
             mStagedSessions.remove(sessionInfo.sessionId);
         }
     }
+
+    void restoreSession(@NonNull PackageInstallerSession session) {
+        updateStoredSession(session);
+        // TODO(b/118865310): This method is called when PackageInstaller is re-instantiated, e.g.
+        // at reboot. Staging manager should at this point recover state from apexd and decide what
+        // to do with the session.
+    }
 }
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index dd04652..aaa1874 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -620,9 +620,6 @@
                         && callingUid != Process.SYSTEM_UID) {
                     return true;
                 } else if (String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(value)) {
-                    // Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
-                    // in android.provider.Settings.Secure.putStringForUser(), so we shouldn't come
-                    // here normally, but we still protect it here from a direct provider write.
                     return false;
                 }
                 restriction = UserManager.DISALLOW_SHARE_LOCATION;
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
index e212b04..437ef73 100644
--- a/services/core/java/com/android/server/policy/TEST_MAPPING
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -10,7 +10,7 @@
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
new file mode 100644
index 0000000..45c975b
--- /dev/null
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -0,0 +1,97 @@
+/*
+ * 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.policy.role;
+
+import android.annotation.NonNull;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.os.Debug;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.telephony.SmsApplication;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.role.RoleManagerService;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Logic to retrieve the various legacy(pre-Q) equivalents of role holders.
+ *
+ * Unlike {@link RoleManagerService} this is meant to be pretty high-level to allow for depending
+ * on all kinds of various systems that are historically involved in legacy role resolution,
+ * e.g. {@link SmsApplication}
+ *
+ * @see RoleManagerService#migrateRoleIfNecessary
+ */
+public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHoldersResolver {
+
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "LegacyRoleResolutionPol";
+
+    @NonNull
+    private final Context mContext;
+
+    public LegacyRoleResolutionPolicy(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public List<String> getRoleHolders(String roleName, int userId) {
+        switch (roleName) {
+            case RoleManager.ROLE_SMS: {
+                // Moved over from SmsApplication#getApplication
+                String result = Settings.Secure.getStringForUser(
+                        mContext.getContentResolver(),
+                        Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+
+                if (result == null) {
+                    Collection<SmsApplication.SmsApplicationData> applications =
+                            SmsApplication.getApplicationCollectionAsUser(mContext, userId);
+                    SmsApplication.SmsApplicationData applicationData;
+                    String defaultPackage = mContext.getResources()
+                            .getString(com.android.internal.R.string.default_sms_application);
+                    applicationData =
+                            SmsApplication.getApplicationForPackage(applications, defaultPackage);
+
+                    if (applicationData == null) {
+                        // Are there any applications?
+                        if (applications.size() != 0) {
+                            applicationData =
+                                    (SmsApplication.SmsApplicationData) applications.toArray()[0];
+                        }
+                    }
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Found default sms app: " + applicationData
+                                + " among: " + applications + " from " + Debug.getCallers(4));
+                    }
+                    SmsApplication.SmsApplicationData app = applicationData;
+                    result = app == null ? null : app.mPackageName;
+                }
+
+                return CollectionUtils.singletonOrEmpty(result);
+            }
+            default: {
+                Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
+                return Collections.emptyList();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index 244ccb6..5cbe74c 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,6 +1,4 @@
 michaelwr@google.com
 santoscordon@google.com
 
-per-file BatterySaverPolicy.java=omakoto@google.com
-per-file ShutdownThread.java=fkupolov@google.com
-per-file ThermalManagerService.java=wvw@google.com
\ No newline at end of file
+per-file ThermalManagerService.java=wvw@google.com
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 565bb706..a027873 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -96,6 +96,7 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.batterysaver.BatterySaverController;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
 import com.android.server.power.batterysaver.BatterySaverStateMachine;
 import com.android.server.power.batterysaver.BatterySavingStats;
 
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 02689a9..7d03d82 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -134,10 +134,14 @@
             if (!halConnected) {
                 mHalWrapper = new ThermalHal20Wrapper();
                 halConnected = mHalWrapper.connectToHal();
-                if (!halConnected) {
-                    mHalWrapper = new ThermalHal11Wrapper();
-                    halConnected = mHalWrapper.connectToHal();
-                }
+            }
+            if (!halConnected) {
+                mHalWrapper = new ThermalHal11Wrapper();
+                halConnected = mHalWrapper.connectToHal();
+            }
+            if (!halConnected) {
+                mHalWrapper = new ThermalHal10Wrapper();
+                halConnected = mHalWrapper.connectToHal();
             }
             mHalWrapper.setCallback(this::onTemperatureChangedCallback);
             if (!halConnected) {
@@ -616,6 +620,81 @@
         }
     }
 
+
+    static class ThermalHal10Wrapper extends ThermalHalWrapper {
+        /** Proxy object for the Thermal HAL 1.0 service. */
+        @GuardedBy("mHalLock")
+        private android.hardware.thermal.V1_0.IThermal mThermalHal10 = null;
+
+        @Override
+        protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
+                int type) {
+            synchronized (mHalLock) {
+                List<Temperature> ret = new ArrayList<>();
+                if (mThermalHal10 == null) {
+                    return ret;
+                }
+                try {
+                    mThermalHal10.getTemperatures(
+                            (ThermalStatus status,
+                                    ArrayList<android.hardware.thermal.V1_0.Temperature>
+                                            temperatures) -> {
+                                if (ThermalStatusCode.SUCCESS == status.code) {
+                                    for (android.hardware.thermal.V1_0.Temperature
+                                            temperature : temperatures) {
+                                        if (shouldFilter && type != temperature.type) {
+                                            continue;
+                                        }
+                                        // Thermal HAL 1.0 doesn't report current throttling status
+                                        ret.add(new Temperature(
+                                                temperature.currentValue, temperature.type,
+                                                temperature.name,
+                                                Temperature.THROTTLING_NONE));
+                                    }
+                                } else {
+                                    Slog.e(TAG,
+                                            "Couldn't get temperatures because of HAL error: "
+                                                    + status.debugMessage);
+                                }
+
+                            });
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
+                    connectToHal();
+                }
+                return ret;
+            }
+        }
+
+        @Override
+        protected boolean connectToHal() {
+            synchronized (mHalLock) {
+                try {
+                    mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService();
+                    mThermalHal10.linkToDeath(new DeathRecipient(),
+                            THERMAL_HAL_DEATH_COOKIE);
+                    Slog.i(TAG,
+                            "Thermal HAL 1.0 service connected, no thermal call back will be "
+                                    + "called due to legacy API.");
+                } catch (NoSuchElementException | RemoteException e) {
+                    Slog.e(TAG,
+                            "Thermal HAL 1.0 service not connected.");
+                    mThermalHal10 = null;
+                }
+                return (mThermalHal10 != null);
+            }
+        }
+
+        @Override
+        protected void dump(PrintWriter pw, String prefix) {
+            synchronized (mHalLock) {
+                pw.print(prefix);
+                pw.println("ThermalHAL 1.0 connected: " + (mThermalHal10 != null ? "yes"
+                        : "no"));
+            }
+        }
+    }
+
     static class ThermalHal11Wrapper extends ThermalHalWrapper {
         /** Proxy object for the Thermal HAL 1.1 service. */
         @GuardedBy("mHalLock")
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 6400c88..1d74350 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -35,13 +35,13 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy;
-import com.android.server.power.BatterySaverPolicy.BatterySaverPolicyListener;
 import com.android.server.power.PowerManagerService;
+import com.android.server.power.batterysaver.BatterySaverPolicy.BatterySaverPolicyListener;
 import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
 import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
 import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
@@ -158,10 +158,9 @@
         mBatterySavingStats = batterySavingStats;
 
         // Initialize plugins.
-        final ArrayList<Plugin> plugins = new ArrayList<>();
-        plugins.add(new BatterySaverLocationPlugin(mContext));
-
-        mPlugins = plugins.toArray(new Plugin[plugins.size()]);
+        mPlugins = new Plugin[] {
+                new BatterySaverLocationPlugin(mContext)
+        };
     }
 
     /**
@@ -217,7 +216,7 @@
             super(looper);
         }
 
-        public void postStateChanged(boolean sendBroadcast, int reason) {
+        void postStateChanged(boolean sendBroadcast, int reason) {
             obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
                     ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
         }
@@ -244,9 +243,8 @@
         }
     }
 
-    /**
-     * Called by {@link PowerManagerService} to update the battery saver state.
-     */
+    /** Enable or disable full battery saver. */
+    @VisibleForTesting
     public void enableBatterySaver(boolean enable, int reason) {
         synchronized (mLock) {
             if (mEnabled == enable) {
@@ -311,7 +309,7 @@
                     reason);
             mPreviouslyEnabled = mEnabled;
 
-            listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
+            listeners = mListeners.toArray(new LowPowerModeListener[0]);
 
             enabled = mEnabled;
             mIsInteractive = isInteractive;
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
similarity index 98%
rename from services/core/java/com/android/server/power/BatterySaverPolicy.java
rename to services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index cedb548..48a041e 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.server.power;
+package com.android.server.power.batterysaver;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -36,21 +36,19 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ConcurrentUtils;
-import com.android.server.power.batterysaver.BatterySavingStats;
-import com.android.server.power.batterysaver.CpuFrequencies;
+import com.android.server.power.PowerManagerService;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Class to decide whether to turn on battery saver mode for specific service
+ * Class to decide whether to turn on battery saver mode for specific services.
  *
  * IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy.
  * Do not call out with the lock held, such as AccessibilityManager. (Settings provider is okay.)
  *
- * Test:
- atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+ * Test: atest com.android.server.power.batterysaver.BatterySaverPolicyTest.java
  */
 public class BatterySaverPolicy extends ContentObserver {
     private static final String TAG = "BatterySaverPolicy";
@@ -200,8 +198,10 @@
         onChange(true, null);
     }
 
+    @VisibleForTesting
     public void addListener(BatterySaverPolicyListener listener) {
         synchronized (mLock) {
+            // TODO: set this in the constructor instead
             mListeners.add(listener);
         }
     }
@@ -244,7 +244,7 @@
             // Update.
             updateConstantsLocked(setting, deviceSpecificSetting);
 
-            listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
+            listeners = mListeners.toArray(new BatterySaverPolicyListener[0]);
         }
 
         // Notify the listeners.
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index a60f16d..b7f28da 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -37,7 +37,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.EventLogTags;
-import com.android.server.power.BatterySaverPolicy;
 import com.android.server.power.BatterySaverStateMachineProto;
 
 import java.io.PrintWriter;
@@ -229,8 +228,8 @@
     }
 
     /**
-     * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable},
-     * it'll be first removed before a new one is posted.
+     * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable} is
+     * already registered, it'll be first removed before being re-posted.
      */
     @VisibleForTesting
     void runOnBgThreadLazy(Runnable r, int delayMillis) {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 8213205..79b44eb 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -29,7 +29,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy;
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index f37ca12..b488337 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -35,6 +35,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -92,6 +93,15 @@
     @NonNull
     private final Object mLock = new Object();
 
+    @NonNull
+    private final RoleHoldersResolver mLegacyRoleResolver;
+
+    /** @see #getRoleHolders(String, int) */
+    public interface RoleHoldersResolver {
+        /** @return a list of packages that hold a given role for a given user */
+        List<String> getRoleHolders(String roleName, int userId);
+    }
+
     /**
      * Maps user id to its state.
      */
@@ -118,9 +128,12 @@
     @NonNull
     private final Handler mListenerHandler = FgThread.getHandler();
 
-    public RoleManagerService(@NonNull Context context) {
+    public RoleManagerService(@NonNull Context context,
+            @NonNull RoleHoldersResolver legacyRoleResolver) {
         super(context);
 
+        mLegacyRoleResolver = legacyRoleResolver;
+
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
 
@@ -175,10 +188,17 @@
     private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
         RoleUserState userState;
         userState = getOrCreateUserState(userId);
+
         String packagesHash = computeComponentStateHash(userId);
         String oldPackagesHash = userState.getPackagesHash();
         boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
         if (needGrant) {
+
+            //TODO gradually add more role migrations statements here for remaining roles
+            // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
+            // for a given role before adding a migration statement for it here
+            migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
+
             // Some vital packages state has changed since last role grant
             // Run grants again
             Slog.i(LOG_TAG, "Granting default permissions...");
@@ -205,6 +225,20 @@
         }
     }
 
+    private void migrateRoleIfNecessary(String role, @UserIdInt int userId) {
+        // Any role for which we have a record are already migrated
+        RoleUserState userState = getOrCreateUserState(userId);
+        if (!userState.isRoleAvailable(role)) {
+            userState.addRoleName(role);
+            List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId);
+            Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
+            int size = roleHolders.size();
+            for (int i = 0; i < size; i++) {
+                userState.addRoleHolder(role, roleHolders.get(i));
+            }
+        }
+    }
+
     @Nullable
     private static String computeComponentStateHash(@UserIdInt int userId) {
         PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
@@ -372,6 +406,7 @@
         @Nullable
         private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
                 @UserIdInt int userId) {
+            migrateRoleIfNecessary(roleName, userId);
             RoleUserState userState = getOrCreateUserState(userId);
             return userState.getRoleHolders(roleName);
         }
@@ -530,6 +565,17 @@
         }
 
         @Override
+        public String getDefaultSmsPackage(int userId) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                return CollectionUtils.firstOrNull(
+                        getRoleHoldersAsUser(RoleManager.ROLE_SMS, userId));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                 @Nullable String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), LOG_TAG, fout)) {
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 630a39c..69e1449 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -205,6 +205,28 @@
     }
 
     /**
+     * Adds the given role, effectively marking it as {@link #isRoleAvailable available}
+     *
+     * @param roleName the name of the role
+     *
+     * @return whether any changes were made
+     */
+    public boolean addRoleName(@NonNull String roleName) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+
+            if (!mRoles.containsKey(roleName)) {
+                mRoles.put(roleName, new ArraySet<>());
+                Slog.i(LOG_TAG, "Added new role: " + roleName);
+                scheduleWriteFileLocked();
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
      * Set the names of all available roles.
      *
      * @param roleNames the names of all the available roles
@@ -231,13 +253,7 @@
 
             int roleNamesSize = roleNames.size();
             for (int i = 0; i < roleNamesSize; i++) {
-                String roleName = roleNames.get(i);
-
-                if (!mRoles.containsKey(roleName)) {
-                    mRoles.put(roleName, new ArraySet<>());
-                    Slog.i(LOG_TAG, "Added new role: " + roleName);
-                    changed = true;
-                }
+                changed |= addRoleName(roleNames.get(i));
             }
 
             if (changed) {
diff --git a/services/core/java/com/android/server/rollback/PackageRollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java
similarity index 65%
rename from services/core/java/com/android/server/rollback/PackageRollbackData.java
rename to services/core/java/com/android/server/rollback/RollbackData.java
index 15d1242..f0589aa 100644
--- a/services/core/java/com/android/server/rollback/PackageRollbackData.java
+++ b/services/core/java/com/android/server/rollback/RollbackData.java
@@ -20,17 +20,21 @@
 
 import java.io.File;
 import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
- * Information about a rollback available for a particular package.
- * This is similar to {@link PackageRollbackInfo}, but extended with
- * additional information for internal bookkeeping.
+ * Information about a rollback available for a set of atomically installed
+ * packages.
  */
-class PackageRollbackData {
-    public final PackageRollbackInfo info;
+class RollbackData {
+    /**
+     * The per-package rollback information.
+     */
+    public final List<PackageRollbackInfo> packages = new ArrayList<>();
 
     /**
-     * The directory where the apk backup is stored.
+     * The directory where the rollback data is stored.
      */
     public final File backupDir;
 
@@ -38,12 +42,9 @@
      * The time when the upgrade occurred, for purposes of expiring
      * rollback data.
      */
-    public final Instant timestamp;
+    public Instant timestamp;
 
-    PackageRollbackData(PackageRollbackInfo info,
-            File backupDir, Instant timestamp) {
-        this.info = info;
+    RollbackData(File backupDir) {
         this.backupDir = backupDir;
-        this.timestamp = timestamp;
     }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 0c21312..8021265 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -63,9 +63,11 @@
 import java.time.format.DateTimeParseException;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -86,10 +88,20 @@
     // mLock is held when they are called.
     private final Object mLock = new Object();
 
+    // Package rollback data for rollback-enabled installs that have not yet
+    // been committed. Maps from sessionId to rollback data.
+    @GuardedBy("mLock")
+    private final Map<Integer, RollbackData> mPendingRollbacks = new HashMap<>();
+
+    // Map from child session id's for enabled rollbacks to their
+    // corresponding parent session ids.
+    @GuardedBy("mLock")
+    private final Map<Integer, Integer> mChildSessions = new HashMap<>();
+
     // Package rollback data available to be used for rolling back a package.
     // This list is null until the rollback data has been loaded.
     @GuardedBy("mLock")
-    private List<PackageRollbackData> mAvailableRollbacks;
+    private List<RollbackData> mAvailableRollbacks;
 
     // The list of recently executed rollbacks.
     // This list is null until the rollback data has been loaded.
@@ -102,14 +114,25 @@
     // to store this data:
     //   /data/rollback/
     //      available/
-    //          com.package.A-XXX/
-    //              base.apk
-    //              rollback.json
-    //          com.package.B-YYY/
-    //              base.apk
-    //              rollback.json
+    //          XXX/
+    //              com.package.A/
+    //                  base.apk
+    //                  info.json
+    //              enabled.txt
+    //          YYY/
+    //              com.package.B/
+    //                  base.apk
+    //                  info.json
+    //              enabled.txt
     //      recently_executed.json
-    // TODO: Use AtomicFile for rollback.json and recently_executed.json.
+    //
+    // * XXX, YYY are random strings from Files.createTempDirectory
+    // * info.json contains the package version to roll back from/to.
+    // * enabled.txt contains a timestamp for when the rollback was first
+    //   made available. This file is not written until the rollback is made
+    //   available.
+    //
+    // TODO: Use AtomicFile for all the .json files?
     private final File mRollbackDataDir;
     private final File mAvailableRollbacksDir;
     private final File mRecentlyExecutedRollbacksFile;
@@ -135,6 +158,9 @@
         // expiration.
         getHandler().post(() -> ensureRollbackDataLoaded());
 
+        PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
+        installer.registerSessionCallback(new SessionCallback(), getHandler());
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
         filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
@@ -199,27 +225,23 @@
                 android.Manifest.permission.MANAGE_ROLLBACKS,
                 "getAvailableRollback");
 
-        PackageRollbackInfo.PackageVersion installedVersion =
-                getInstalledPackageVersion(packageName);
-        if (installedVersion == null) {
+        RollbackData data = getRollbackForPackage(packageName);
+        if (data == null) {
             return null;
         }
 
-        synchronized (mLock) {
-            // TODO: Have ensureRollbackDataLoadedLocked return the list of
-            // available rollbacks, to hopefully avoid forgetting to call it?
-            ensureRollbackDataLoadedLocked();
-            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
-                PackageRollbackData data = mAvailableRollbacks.get(i);
-                if (data.info.packageName.equals(packageName)
-                        && data.info.higherVersion.equals(installedVersion)) {
-                    // TODO: For atomic installs, check all dependent packages
-                    // for available rollbacks and include that info here.
-                    return new RollbackInfo(data.info);
-                }
+        // Note: The rollback for the package ought to be for the currently
+        // installed version, otherwise the rollback data is out of date. In
+        // that rare case, we'll check when we execute the rollback whether
+        // it's out of date or not, so no need to check package versions here.
+
+        for (PackageRollbackInfo info : data.packages) {
+            if (info.packageName.equals(packageName)) {
+                // TODO: Once the RollbackInfo API supports info about
+                // dependant packages, add that info here.
+                return new RollbackInfo(info);
             }
         }
-
         return null;
     }
 
@@ -229,16 +251,14 @@
                 android.Manifest.permission.MANAGE_ROLLBACKS,
                 "getPackagesWithAvailableRollbacks");
 
-        // TODO: This may return packages whose rollback is out of date or
-        // expired.  Presumably that's okay because the package rollback could
-        // be expired anyway between when the caller calls this method and
-        // when the caller calls getAvailableRollback for more details.
         final Set<String> packageNames = new HashSet<>();
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
             for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
-                PackageRollbackData data = mAvailableRollbacks.get(i);
-                packageNames.add(data.info.packageName);
+                RollbackData data = mAvailableRollbacks.get(i);
+                for (PackageRollbackInfo info : data.packages) {
+                    packageNames.add(info.packageName);
+                }
             }
         }
         return new StringParceledListSlice(new ArrayList<>(packageNames));
@@ -279,47 +299,49 @@
      */
     private void executeRollbackInternal(RollbackInfo rollback,
             String callerPackageName, IntentSender statusReceiver) {
-        String packageName = rollback.targetPackage.packageName;
-        Log.i(TAG, "Initiating rollback of " + packageName);
+        String targetPackageName = rollback.targetPackage.packageName;
+        Log.i(TAG, "Initiating rollback of " + targetPackageName);
 
-        PackageRollbackInfo.PackageVersion installedVersion =
-                getInstalledPackageVersion(packageName);
-        if (installedVersion == null) {
-            // TODO: Test this case
-            sendFailure(statusReceiver, "Target package to roll back is not installed");
+        // Get the latest RollbackData for the target package.
+        RollbackData data = getRollbackForPackage(targetPackageName);
+        if (data == null) {
+            sendFailure(statusReceiver, "No rollback available for package.");
             return;
         }
 
-        if (!rollback.targetPackage.higherVersion.equals(installedVersion)) {
-            // TODO: Test this case
-            sendFailure(statusReceiver, "Target package version to roll back not installed.");
-            return;
+        // Verify the latest rollback matches the version requested.
+        // TODO: Check dependant packages too once RollbackInfo includes that
+        // information.
+        for (PackageRollbackInfo info : data.packages) {
+            if (info.packageName.equals(targetPackageName)
+                    && !rollback.targetPackage.higherVersion.equals(info.higherVersion)) {
+                sendFailure(statusReceiver, "Rollback is out of date.");
+                return;
+            }
         }
 
+        // Verify the RollbackData is up to date with what's installed on
+        // device.
         // TODO: We assume that between now and the time we commit the
         // downgrade install, the currently installed package version does not
         // change. This is not safe to assume, particularly in the case of a
         // rollback racing with a roll-forward fix of a buggy package.
         // Figure out how to ensure we don't commit the rollback if
         // roll forward happens at the same time.
-        PackageRollbackData data = null;
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
-                PackageRollbackData available = mAvailableRollbacks.get(i);
-                // TODO: Check if available.info.lowerVersion matches
-                // rollback.targetPackage.lowerVersion?
-                if (available.info.packageName.equals(packageName)
-                        && available.info.higherVersion.equals(installedVersion)) {
-                    data = available;
-                    break;
-                }
+        for (PackageRollbackInfo info : data.packages) {
+            PackageRollbackInfo.PackageVersion installedVersion =
+                    getInstalledPackageVersion(info.packageName);
+            if (installedVersion == null) {
+                // TODO: Test this case
+                sendFailure(statusReceiver, "Package to roll back is not installed");
+                return;
             }
-        }
 
-        if (data == null) {
-            sendFailure(statusReceiver, "Rollback not available");
-            return;
+            if (!info.higherVersion.equals(installedVersion)) {
+                // TODO: Test this case
+                sendFailure(statusReceiver, "Package version to roll back not installed.");
+                return;
+            }
         }
 
         // Get a context for the caller to use to install the downgraded
@@ -334,29 +356,39 @@
 
         PackageManager pm = context.getPackageManager();
         try {
-            PackageInstaller.Session session = null;
-
             PackageInstaller packageInstaller = pm.getPackageInstaller();
-            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+            PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
                     PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-            params.setAllowDowngrade(true);
-            int sessionId = packageInstaller.createSession(params);
-            session = packageInstaller.openSession(sessionId);
+            parentParams.setAllowDowngrade(true);
+            parentParams.setMultiPackage();
+            int parentSessionId = packageInstaller.createSession(parentParams);
+            PackageInstaller.Session parentSession = packageInstaller.openSession(parentSessionId);
 
-            // TODO: Will it always be called "base.apk"? What about splits?
-            File baseApk = new File(data.backupDir, "base.apk");
-            try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(baseApk,
-                    ParcelFileDescriptor.MODE_READ_ONLY)) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    session.write("base.apk", 0, baseApk.length(), fd);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
+            for (PackageRollbackInfo info : data.packages) {
+                PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+                params.setAllowDowngrade(true);
+                int sessionId = packageInstaller.createSession(params);
+                PackageInstaller.Session session = packageInstaller.openSession(sessionId);
+
+                // TODO: Will it always be called "base.apk"? What about splits?
+                // What about apex?
+                File packageDir = new File(data.backupDir, info.packageName);
+                File baseApk = new File(packageDir, "base.apk");
+                try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(baseApk,
+                        ParcelFileDescriptor.MODE_READ_ONLY)) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        session.write("base.apk", 0, baseApk.length(), fd);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
                 }
+                parentSession.addChildSessionId(sessionId);
             }
 
             final LocalIntentReceiver receiver = new LocalIntentReceiver();
-            session.commit(receiver.getIntentSender());
+            parentSession.commit(receiver.getIntentSender());
 
             Intent result = receiver.getResult();
             int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
@@ -371,13 +403,14 @@
             sendSuccess(statusReceiver);
 
             Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
-                    Uri.fromParts("package", packageName, Manifest.permission.MANAGE_ROLLBACKS));
+                    Uri.fromParts("package", targetPackageName,
+                        Manifest.permission.MANAGE_ROLLBACKS));
 
             // TODO: This call emits the warning "Calling a method in the
             // system process without a qualified user". Fix that.
             mContext.sendBroadcast(broadcast);
         } catch (IOException e) {
-            Log.e(TAG, "Unable to roll back " + packageName, e);
+            Log.e(TAG, "Unable to roll back " + targetPackageName, e);
             sendFailure(statusReceiver, "IOException: " + e.toString());
             return;
         }
@@ -408,12 +441,15 @@
         // testing anyway.
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
-            Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
+            Iterator<RollbackData> iter = mAvailableRollbacks.iterator();
             while (iter.hasNext()) {
-                PackageRollbackData data = iter.next();
-                if (data.info.packageName.equals(packageName)) {
-                    iter.remove();
-                    removeFile(data.backupDir);
+                RollbackData data = iter.next();
+                for (PackageRollbackInfo info : data.packages) {
+                    if (info.packageName.equals(packageName)) {
+                        iter.remove();
+                        removeFile(data.backupDir);
+                        break;
+                    }
                 }
             }
         }
@@ -453,27 +489,41 @@
         mAvailableRollbacksDir.mkdirs();
         mAvailableRollbacks = new ArrayList<>();
         for (File rollbackDir : mAvailableRollbacksDir.listFiles()) {
-            if (rollbackDir.isDirectory()) {
-                // TODO: How to detect and clean up an invalid rollback
-                // directory? We don't know if it's invalid because something
-                // went wrong, or if it's only temporarily invalid because
-                // it's in the process of being created.
+            File enabledFile = new File(rollbackDir, "enabled.txt");
+            // TODO: Delete any directories without an enabled.txt? That could
+            // potentially delete pending rollback data if reloadPersistedData
+            // is called, though there's no reason besides testing for that to
+            // be called.
+            if (rollbackDir.isDirectory() && enabledFile.isFile()) {
+                RollbackData data = new RollbackData(rollbackDir);
                 try {
-                    File jsonFile = new File(rollbackDir, "rollback.json");
-                    String jsonString = IoUtils.readFileAsString(jsonFile.getAbsolutePath());
-                    JSONObject jsonObject = new JSONObject(jsonString);
-                    String packageName = jsonObject.getString("packageName");
-                    long higherVersionCode = jsonObject.getLong("higherVersionCode");
-                    long lowerVersionCode = jsonObject.getLong("lowerVersionCode");
-                    Instant timestamp = Instant.parse(jsonObject.getString("timestamp"));
-                    PackageRollbackData data = new PackageRollbackData(
-                            new PackageRollbackInfo(packageName,
-                                new PackageRollbackInfo.PackageVersion(higherVersionCode),
-                                new PackageRollbackInfo.PackageVersion(lowerVersionCode)),
-                            rollbackDir, timestamp);
+                    PackageRollbackInfo info = null;
+                    for (File packageDir : rollbackDir.listFiles()) {
+                        if (packageDir.isDirectory()) {
+                            File jsonFile = new File(packageDir, "info.json");
+                            String jsonString = IoUtils.readFileAsString(
+                                    jsonFile.getAbsolutePath());
+                            JSONObject jsonObject = new JSONObject(jsonString);
+                            String packageName = jsonObject.getString("packageName");
+                            long higherVersionCode = jsonObject.getLong("higherVersionCode");
+                            long lowerVersionCode = jsonObject.getLong("lowerVersionCode");
+
+                            data.packages.add(new PackageRollbackInfo(packageName,
+                                        new PackageRollbackInfo.PackageVersion(higherVersionCode),
+                                        new PackageRollbackInfo.PackageVersion(lowerVersionCode)));
+                        }
+                    }
+
+                    if (data.packages.isEmpty()) {
+                        throw new IOException("No package rollback info found");
+                    }
+
+                    String enabledString = IoUtils.readFileAsString(enabledFile.getAbsolutePath());
+                    data.timestamp = Instant.parse(enabledString.trim());
                     mAvailableRollbacks.add(data);
                 } catch (IOException | JSONException | DateTimeParseException e) {
                     Log.e(TAG, "Unable to read rollback data at " + rollbackDir, e);
+                    removeFile(rollbackDir);
                 }
             }
         }
@@ -521,13 +571,16 @@
 
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
-            Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
+            Iterator<RollbackData> iter = mAvailableRollbacks.iterator();
             while (iter.hasNext()) {
-                PackageRollbackData data = iter.next();
-                if (data.info.packageName.equals(packageName)
-                        && !data.info.higherVersion.equals(installedVersion)) {
-                    iter.remove();
-                    removeFile(data.backupDir);
+                RollbackData data = iter.next();
+                for (PackageRollbackInfo info : data.packages) {
+                    if (info.packageName.equals(packageName)
+                            && !info.higherVersion.equals(installedVersion)) {
+                        iter.remove();
+                        removeFile(data.backupDir);
+                        break;
+                    }
                 }
             }
         }
@@ -643,9 +696,9 @@
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
 
-            Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
+            Iterator<RollbackData> iter = mAvailableRollbacks.iterator();
             while (iter.hasNext()) {
-                PackageRollbackData data = iter.next();
+                RollbackData data = iter.next();
                 if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
                     iter.remove();
                     removeFile(data.backupDir);
@@ -673,6 +726,23 @@
         return mHandlerThread.getThreadHandler();
     }
 
+    // Returns true if <code>session</code> has installFlags and code path
+    // matching the installFlags and new package code path given to
+    // enableRollback.
+    private boolean sessionMatchesForEnableRollback(PackageInstaller.SessionInfo session,
+            int installFlags, File newPackageCodePath) {
+        if (session == null || session.resolvedBaseCodePath == null) {
+            return false;
+        }
+
+        File packageCodePath = new File(session.resolvedBaseCodePath).getParentFile();
+        if (newPackageCodePath.equals(packageCodePath) && installFlags == session.installFlags) {
+            return true;
+        }
+
+        return false;
+    }
+
     /**
      * Called via broadcast by the package manager when a package is being
      * staged for install with rollback enabled. Called before the package has
@@ -705,6 +775,34 @@
         String packageName = newPackage.packageName;
         Log.i(TAG, "Enabling rollback for install of " + packageName);
 
+        // Figure out the session id associated with this install.
+        int parentSessionId = PackageInstaller.SessionInfo.INVALID_ID;
+        int childSessionId = PackageInstaller.SessionInfo.INVALID_ID;
+        PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
+        for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
+            if (info.isMultiPackage()) {
+                for (int childId : info.getChildSessionIds()) {
+                    PackageInstaller.SessionInfo child = installer.getSessionInfo(childId);
+                    if (sessionMatchesForEnableRollback(child, installFlags, newPackageCodePath)) {
+                        // TODO: Check we only have one matching session?
+                        parentSessionId = info.getSessionId();
+                        childSessionId = childId;
+                    }
+                }
+            } else {
+                if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) {
+                    // TODO: Check we only have one matching session?
+                    parentSessionId = info.getSessionId();
+                    childSessionId = parentSessionId;
+                }
+            }
+        }
+
+        if (parentSessionId == PackageInstaller.SessionInfo.INVALID_ID) {
+            Log.e(TAG, "Unable to find session id for enabled rollback.");
+            return false;
+        }
+
         PackageRollbackInfo.PackageVersion newVersion =
                 new PackageRollbackInfo.PackageVersion(newPackage.versionCode);
 
@@ -720,52 +818,53 @@
         PackageRollbackInfo.PackageVersion installedVersion =
                 new PackageRollbackInfo.PackageVersion(installedPackage.getLongVersionCode());
 
-        File backupDir;
+        PackageRollbackInfo info = new PackageRollbackInfo(
+                packageName, newVersion, installedVersion);
+
+        RollbackData data;
         try {
-            backupDir = Files.createTempDirectory(
-                mAvailableRollbacksDir.toPath(), packageName + "-").toFile();
+            synchronized (mLock) {
+                mChildSessions.put(childSessionId, parentSessionId);
+                data = mPendingRollbacks.get(parentSessionId);
+                if (data == null) {
+                    File backupDir = Files.createTempDirectory(
+                            mAvailableRollbacksDir.toPath(), null).toFile();
+                    data = new RollbackData(backupDir);
+                    mPendingRollbacks.put(parentSessionId, data);
+                }
+                data.packages.add(info);
+            }
         } catch (IOException e) {
             Log.e(TAG, "Unable to create rollback for " + packageName, e);
             return false;
         }
 
-        // TODO: Should the timestamp be for when we commit the install, not
-        // when we create the pending one?
-        Instant timestamp = Instant.now();
+        File packageDir = new File(data.backupDir, packageName);
+        packageDir.mkdirs();
         try {
             JSONObject json = new JSONObject();
             json.put("packageName", packageName);
             json.put("higherVersionCode", newVersion.versionCode);
             json.put("lowerVersionCode", installedVersion.versionCode);
-            json.put("timestamp", timestamp.toString());
 
-            File jsonFile = new File(backupDir, "rollback.json");
+            File jsonFile = new File(packageDir, "info.json");
             PrintWriter pw = new PrintWriter(jsonFile);
             pw.println(json.toString());
             pw.close();
         } catch (IOException | JSONException e) {
             Log.e(TAG, "Unable to create rollback for " + packageName, e);
-            removeFile(backupDir);
+            removeFile(packageDir);
             return false;
         }
 
         // TODO: Copy by hard link instead to save on cpu and storage space?
-        int status = PackageManagerServiceUtils.copyPackage(installedPackage.codePath, backupDir);
+        int status = PackageManagerServiceUtils.copyPackage(installedPackage.codePath, packageDir);
         if (status != PackageManager.INSTALL_SUCCEEDED) {
             Log.e(TAG, "Unable to copy package for rollback for " + packageName);
-            removeFile(backupDir);
+            removeFile(packageDir);
             return false;
         }
 
-        PackageRollbackData data = new PackageRollbackData(
-                new PackageRollbackInfo(packageName, newVersion, installedVersion),
-                backupDir, timestamp);
-
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            mAvailableRollbacks.add(data);
-        }
-
         return true;
     }
 
@@ -829,4 +928,87 @@
 
         return new PackageRollbackInfo.PackageVersion(pkgInfo.getLongVersionCode());
     }
+
+    private class SessionCallback extends PackageInstaller.SessionCallback {
+
+        @Override
+        public void onCreated(int sessionId) { }
+
+        @Override
+        public void onBadgingChanged(int sessionId) { }
+
+        @Override
+        public void onActiveChanged(int sessionId, boolean active) { }
+
+        @Override
+        public void onProgressChanged(int sessionId, float progress) { }
+
+        @Override
+        public void onFinished(int sessionId, boolean success) {
+            RollbackData data = null;
+            synchronized (mLock) {
+                Integer parentSessionId = mChildSessions.remove(sessionId);
+                if (parentSessionId != null) {
+                    sessionId = parentSessionId;
+                }
+                data = mPendingRollbacks.remove(sessionId);
+            }
+
+            if (data != null) {
+                if (success) {
+                    try {
+                        data.timestamp = Instant.now();
+                        File enabledFile = new File(data.backupDir, "enabled.txt");
+                        PrintWriter pw = new PrintWriter(enabledFile);
+                        pw.println(data.timestamp.toString());
+                        pw.close();
+
+                        synchronized (mLock) {
+                            // Note: There is a small window of time between when
+                            // the session has been committed by the package
+                            // manager and when we make the rollback available
+                            // here. Presumably the window is small enough that
+                            // nobody will want to roll back the newly installed
+                            // package before we make the rollback available.
+                            // TODO: We'll lose the rollback data if the
+                            // device reboots between when the session is
+                            // committed and this point. Revisit this after
+                            // adding support for rollback of staged installs.
+                            ensureRollbackDataLoadedLocked();
+                            mAvailableRollbacks.add(data);
+                        }
+                    } catch (IOException e) {
+                        Log.e(TAG, "Unable to enable rollback", e);
+                        removeFile(data.backupDir);
+                    }
+                } else {
+                    // The install session was aborted, clean up the pending
+                    // install.
+                    removeFile(data.backupDir);
+                }
+            }
+        }
+    }
+
+    /*
+     * Returns the RollbackData, if any, for an available rollback that would
+     * roll back the given package. Note: This assumes we have at most one
+     * available rollback for a given package at any one time.
+     */
+    private RollbackData getRollbackForPackage(String packageName) {
+        synchronized (mLock) {
+            // TODO: Have ensureRollbackDataLoadedLocked return the list of
+            // available rollbacks, to hopefully avoid forgetting to call it?
+            ensureRollbackDataLoadedLocked();
+            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+                RollbackData data = mAvailableRollbacks.get(i);
+                for (PackageRollbackInfo info : data.packages) {
+                    if (info.packageName.equals(packageName)) {
+                        return data;
+                    }
+                }
+            }
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 839ed30..b1db46f 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -36,6 +36,7 @@
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -59,6 +60,8 @@
     /** The maximum size of signature file.  This is just to avoid potential abuse. */
     private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
 
+    private static final int COMMON_LINUX_PAGE_SIZE_IN_BYTES = 4096;
+
     private static final boolean DEBUG = false;
 
     /** Returns true if the given file looks like containing an fs-verity signature. */
@@ -71,6 +74,48 @@
         return filePath + FSVERITY_SIGNATURE_FILE_EXTENSION;
     }
 
+    /** Generates Merkle tree and fs-verity metadata then enables fs-verity. */
+    public static void setUpFsverity(@NonNull String filePath, String signaturePath)
+            throws IOException, DigestException, NoSuchAlgorithmException {
+        final PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(Paths.get(signaturePath)));
+        final byte[] expectedMeasurement = pkcs7.getContentInfo().getContentBytes();
+        if (DEBUG) {
+            Slog.d(TAG, "Enabling fs-verity with signed fs-verity measurement "
+                    + bytesToString(expectedMeasurement));
+            Slog.d(TAG, "PKCS#7 info: " + pkcs7);
+        }
+
+        final TrackedBufferFactory bufferFactory = new TrackedBufferFactory();
+        final byte[] actualMeasurement = generateFsverityMetadata(filePath, signaturePath,
+                bufferFactory);
+        try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
+            FileChannel ch = raf.getChannel();
+            ch.position(roundUpToNextMultiple(ch.size(), COMMON_LINUX_PAGE_SIZE_IN_BYTES));
+            ByteBuffer buffer = bufferFactory.getBuffer();
+
+            long offset = buffer.position();
+            long size = buffer.limit();
+            while (offset < size) {
+                long s = ch.write(buffer);
+                offset += s;
+                size -= s;
+            }
+        }
+
+        if (!Arrays.equals(expectedMeasurement, actualMeasurement)) {
+            throw new SecurityException("fs-verity measurement mismatch: "
+                    + bytesToString(actualMeasurement) + " != "
+                    + bytesToString(expectedMeasurement));
+        }
+
+        // This can fail if the public key is not already in .fs-verity kernel keyring.
+        int errno = enableFsverityNative(filePath);
+        if (errno != 0) {
+            throw new IOException("Failed to enable fs-verity on " + filePath + ": "
+                    + Os.strerror(errno));
+        }
+    }
+
     /** Returns whether the file has fs-verity enabled. */
     public static boolean hasFsverity(@NonNull String filePath) {
         // NB: only measure but not check the actual measurement here. As long as this succeeds,
@@ -87,36 +132,18 @@
     }
 
     /**
-     * Generates Merkle tree and fs-verity metadata.
+     * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped.
      *
      * @return {@code SetupResult} that contains the result code, and when success, the
      *         {@code FileDescriptor} to read all the data from.
      */
-    public static SetupResult generateApkVeritySetupData(@NonNull String apkPath,
-            String signaturePath, boolean skipSigningBlock) {
+    public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) {
         if (DEBUG) {
-            Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file "
-                    + signaturePath);
+            Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath);
         }
         SharedMemory shm = null;
         try {
-            byte[] signedVerityHash;
-            if (skipSigningBlock) {
-                signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
-            } else {
-                Path path = Paths.get(signaturePath);
-                if (Files.exists(path)) {
-                    // TODO(112037636): fail early if the signing key is not in .fs-verity keyring.
-                    PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path));
-                    signedVerityHash = pkcs7.getContentInfo().getContentBytes();
-                    if (DEBUG) {
-                        Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash));
-                    }
-                } else {
-                    signedVerityHash = null;
-                }
-            }
-
+            final byte[] signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
             if (signedVerityHash == null) {
                 if (DEBUG) {
                     Slog.d(TAG, "Skip verity tree generation since there is no signed root hash");
@@ -124,8 +151,8 @@
                 return SetupResult.skipped();
             }
 
-            Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath,
-                    signaturePath, signedVerityHash, skipSigningBlock);
+            Pair<SharedMemory, Integer> result =
+                    generateFsVerityIntoSharedMemory(apkPath, signedVerityHash);
             shm = result.first;
             int contentSize = result.second;
             FileDescriptor rfd = shm.getFileDescriptor();
@@ -156,7 +183,7 @@
      * {@see ApkSignatureVerifier#getVerityRootHash(String)}.
      */
     public static byte[] getVerityRootHash(@NonNull String apkPath)
-            throws IOException, SignatureNotFoundException, SecurityException {
+            throws IOException, SignatureNotFoundException {
         return ApkSignatureVerifier.getVerityRootHash(apkPath);
     }
 
@@ -172,9 +199,8 @@
      *         includes SHA-256 of fs-verity descriptor and authenticated extensions.
      */
     private static byte[] generateFsverityMetadata(String filePath, String signaturePath,
-            @NonNull TrackedShmBufferFactory trackedBufferFactory)
-            throws IOException, SignatureNotFoundException, SecurityException, DigestException,
-                   NoSuchAlgorithmException {
+            @NonNull ByteBufferFactory trackedBufferFactory)
+            throws IOException, DigestException, NoSuchAlgorithmException {
         try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
             VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree(
                     file, trackedBufferFactory);
@@ -184,6 +210,7 @@
 
             final byte[] measurement = generateFsverityDescriptorAndMeasurement(file,
                     result.rootHash, signaturePath, buffer);
+            buffer.flip();
             return constructFsveritySignedDataNative(measurement);
         }
     }
@@ -243,6 +270,7 @@
         return md.digest();
     }
 
+    private static native int enableFsverityNative(@NonNull String filePath);
     private static native int measureFsverityNative(@NonNull String filePath);
     private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement);
     private static native byte[] constructFsverityDescriptorNative(long fileSize);
@@ -256,18 +284,13 @@
      * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has
      * length equals to the returned {@code Integer}.
      */
-    private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(
-            String apkPath, String signaturePath, @NonNull byte[] expectedRootHash,
-            boolean skipSigningBlock)
-            throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,
+    private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(String apkPath,
+            @NonNull byte[] expectedRootHash)
+            throws IOException, DigestException, NoSuchAlgorithmException,
                    SignatureNotFoundException {
         TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory();
-        byte[] generatedRootHash;
-        if (skipSigningBlock) {
-            generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
-        } else {
-            generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory);
-        }
+        byte[] generatedRootHash =
+                ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
         // We only generate Merkle tree once here, so it's important to make sure the root hash
         // matches the signed one in the apk.
         if (!Arrays.equals(expectedRootHash, generatedRootHash)) {
@@ -345,7 +368,7 @@
         private ByteBuffer mBuffer;
 
         @Override
-        public ByteBuffer create(int capacity) throws SecurityException {
+        public ByteBuffer create(int capacity) {
             try {
                 if (DEBUG) Slog.d(TAG, "Creating shared memory for apk verity");
                 // NB: This method is supposed to be called once according to the contract with
@@ -378,4 +401,30 @@
             return mBuffer == null ? -1 : mBuffer.limit();
         }
     }
+
+    /** A {@code ByteBufferFactory} that tracks the {@code ByteBuffer} it creates. */
+    private static class TrackedBufferFactory implements ByteBufferFactory {
+        private ByteBuffer mBuffer;
+
+        @Override
+        public ByteBuffer create(int capacity) {
+            if (mBuffer != null) {
+                throw new IllegalStateException("Multiple instantiation from this factory");
+            }
+            mBuffer = ByteBuffer.allocate(capacity);
+            return mBuffer;
+        }
+
+        public ByteBuffer getBuffer() {
+            return mBuffer;
+        }
+    }
+
+    /** Round up the number to the next multiple of the divisor. */
+    private static long roundUpToNextMultiple(long number, long divisor) {
+        if (number > (Long.MAX_VALUE - divisor)) {
+            throw new IllegalArgumentException("arithmetic overflow");
+        }
+        return ((number + (divisor - 1)) / divisor) * divisor;
+    }
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index fc21adb..7c1e619 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -598,11 +598,11 @@
     }
 
     @Override
-    public void onBiometricAuthenticated() {
+    public void onBiometricAuthenticated(boolean authenticated) {
         enforceBiometricDialog();
         if (mBar != null) {
             try {
-                mBar.onBiometricAuthenticated();
+                mBar.onBiometricAuthenticated(authenticated);
             } catch (RemoteException ex) {
             }
         }
@@ -641,17 +641,6 @@
         }
     }
 
-    @Override
-    public void showBiometricTryAgain() {
-        enforceBiometricDialog();
-        if (mBar != null) {
-            try {
-                mBar.showBiometricTryAgain();
-            } catch (RemoteException ex) {
-            }
-        }
-    }
-
     // TODO(b/117478341): make it aware of multi-display if needed.
     @Override
     public void disable(int what, IBinder token, String pkg) {
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 2cab63a..ef77140 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -510,7 +510,8 @@
                 Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
                 willBind = mContext.bindServiceAsUser(
                         serviceIntent, mConnection,
-                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+                                | Context.BIND_RESTRICT_ASSOCIATIONS,
                         UserHandle.of(mUserId));
                 mBinding = willBind;
             } finally {
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index 65d5b10..7236d79 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -16,8 +16,6 @@
 
 package com.android.server.textservices;
 
-import static android.view.textservice.TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -43,6 +41,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.inputmethod.InputMethodSystemProperty;
 import android.view.textservice.SpellCheckerInfo;
 import android.view.textservice.SpellCheckerSubtype;
 
@@ -334,7 +333,7 @@
         mContext = context;
         mUserManager = mContext.getSystemService(UserManager.class);
         mSpellCheckerOwnerUserIdMap = new LazyIntToIntMap(callingUserId -> {
-            if (DISABLE_PER_PROFILE_SPELL_CHECKER) {
+            if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
                 final long token = Binder.clearCallingIdentity();
                 try {
                     final UserInfo parent = mUserManager.getProfileParent(callingUserId);
@@ -355,7 +354,7 @@
     private void initializeInternalStateLocked(@UserIdInt int userId) {
         // When DISABLE_PER_PROFILE_SPELL_CHECKER is true, we make sure here that work profile users
         // will never have non-null TextServicesData for their user ID.
-        if (DISABLE_PER_PROFILE_SPELL_CHECKER
+        if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
                 && userId != mSpellCheckerOwnerUserIdMap.get(userId)) {
             return;
         }
@@ -780,7 +779,7 @@
     private TextServicesData getDataFromCallingUserIdLocked(@UserIdInt int callingUserId) {
         final int spellCheckerOwnerUserId = mSpellCheckerOwnerUserIdMap.get(callingUserId);
         final TextServicesData data = mUserData.get(spellCheckerOwnerUserId);
-        if (DISABLE_PER_PROFILE_SPELL_CHECKER) {
+        if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
             if (spellCheckerOwnerUserId != callingUserId) {
                 // Calling process is running under child profile.
                 if (data == null) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 410f864..fcc8284 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -84,6 +84,7 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.EventLog;
+import android.util.FeatureFlagUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -2219,8 +2220,12 @@
         synchronized (mLock) {
             mInAmbientMode = inAmbientMode;
             final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
-            if (data != null && data.connection != null && data.connection.mInfo != null
-                    && data.connection.mInfo.supportsAmbientMode()) {
+            final boolean hasConnection = data != null && data.connection != null;
+            final WallpaperInfo info = hasConnection ? data.connection.mInfo : null;
+
+            // The wallpaper info is null for image wallpaper, also use the engine in this case.
+            if (hasConnection && (info == null && isAodImageWallpaperEnabled()
+                    || info != null && info.supportsAmbientMode())) {
                 // TODO(multi-display) Extends this method with specific display.
                 engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
             } else {
@@ -2237,6 +2242,10 @@
         }
     }
 
+    private boolean isAodImageWallpaperEnabled() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+    }
+
     @Override
     public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
         checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6f8f85f..9f8af50 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -54,6 +54,7 @@
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
 import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
 import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
@@ -142,6 +143,7 @@
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
@@ -387,9 +389,15 @@
     int mRotationAnimationHint = -1;
 
     private boolean mShowWhenLocked;
+    private boolean mInheritShownWhenLocked;
     private boolean mTurnScreenOn;
 
     /**
+     * Current sequencing integer of the configuration, for skipping old activity configurations.
+     */
+    private int mConfigurationSeq;
+
+    /**
      * Temp configs used in {@link #ensureActivityConfiguration(int, boolean)}
      */
     private final Configuration mTmpConfig = new Configuration();
@@ -997,6 +1005,7 @@
                 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
 
         mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+        mInheritShownWhenLocked = (aInfo.privateFlags & FLAG_INHERIT_SHOW_WHEN_LOCKED) != 0;
         mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0;
 
         mRotationAnimationHint = aInfo.rotationAnimation;
@@ -1482,14 +1491,6 @@
         return true;
     }
 
-    /**
-     * @return true if the activity contains windows that have
-     *         {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set
-     */
-    boolean hasDismissKeyguardWindows() {
-        return mAtmService.mWindowManager.containsDismissKeyguardWindow(appToken);
-    }
-
     void makeFinishingLocked() {
         if (finishing) {
             return;
@@ -2568,6 +2569,45 @@
         onRequestedOverrideConfigurationChanged(mTmpConfig);
     }
 
+    @Override
+    void resolveOverrideConfiguration(Configuration newParentConfiguration) {
+        super.resolveOverrideConfiguration(newParentConfiguration);
+
+        // Assign configuration sequence number into hierarchy because there is a different way than
+        // ensureActivityConfiguration() in this class that uses configuration in WindowState during
+        // layout traversals.
+        mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+        getResolvedOverrideConfiguration().seq = mConfigurationSeq;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newParentConfig) {
+        super.onConfigurationChanged(newParentConfig);
+
+        // Configuration's equality doesn't consider seq so if only seq number changes in resolved
+        // override configuration. Therefore ConfigurationContainer doesn't change merged override
+        // configuration, but it's used to push configuration changes so explicitly update that.
+        if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) {
+            onMergedOverrideConfigurationChanged();
+        }
+
+        // TODO(b/80414790): Remove code below after unification.
+        // Same as above it doesn't notify configuration listeners, and consequently AppWindowToken
+        // can't get updated seq number. However WindowState's merged override configuration needs
+        // to have this seq number because that's also used for activity config pushes during layout
+        // traversal. Therefore explicitly update them here.
+        if (mAppWindowToken == null) {
+            return;
+        }
+        final Configuration appWindowTokenRequestedOverrideConfig =
+                mAppWindowToken.getRequestedOverrideConfiguration();
+        if (appWindowTokenRequestedOverrideConfig.seq != getResolvedOverrideConfiguration().seq) {
+            appWindowTokenRequestedOverrideConfig.seq =
+                    getResolvedOverrideConfiguration().seq;
+            mAppWindowToken.onMergedOverrideConfigurationChanged();
+        }
+    }
+
     /** Returns true if the configuration is compatible with this activity. */
     boolean isConfigurationCompatible(Configuration config) {
         final int orientation = mAppWindowToken != null
@@ -3180,16 +3220,45 @@
                 false /* preserveWindows */);
     }
 
+    void setInheritShowWhenLocked(boolean inheritShowWhenLocked) {
+        mInheritShownWhenLocked = inheritShowWhenLocked;
+        mRootActivityContainer.ensureActivitiesVisible(null, 0, false);
+    }
+
     /**
      * @return true if the activity windowing mode is not
-     *         {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and activity contains
-     *         windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the activity
-     *         has set {@link #mShowWhenLocked}.
+     *         {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and a) activity
+     *         contains windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the
+     *         activity has set {@link #mShowWhenLocked}, or b) if the activity has set
+     *         {@link #mInheritShownWhenLocked} and the activity behind this satisfies the
+     *         conditions a) above.
      *         Multi-windowing mode will be exited if true is returned.
      */
     boolean canShowWhenLocked() {
-        return !inPinnedWindowingMode() && (mShowWhenLocked
-                || mAtmService.mWindowManager.containsShowWhenLockedWindow(appToken));
+        if (!inPinnedWindowingMode() && (mShowWhenLocked
+                || (mAppWindowToken != null && mAppWindowToken.containsShowWhenLockedWindow()))) {
+            return true;
+        } else if (mInheritShownWhenLocked) {
+            ActivityRecord r = getActivityBelow();
+            return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked
+                    || (r.mAppWindowToken != null
+                        && r.mAppWindowToken.containsShowWhenLockedWindow()));
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @return an {@link ActivityRecord} of the activity below this activity, or {@code null} if no
+     * such activity exists.
+     */
+    @Nullable
+    private ActivityRecord getActivityBelow() {
+        final int pos = task.mActivities.indexOf(this);
+        if (pos == -1) {
+            throw new IllegalStateException("Activity not found in its task");
+        }
+        return pos == 0 ? null : task.getChildAt(pos - 1);
     }
 
     void setTurnScreenOn(boolean turnScreenOn) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4581a0f..4d7de90 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2204,7 +2204,8 @@
                 .isKeyguardOrAodShowing(displayId);
         final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked();
         final boolean showWhenLocked = r.canShowWhenLocked();
-        final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
+        final boolean dismissKeyguard = r.mAppWindowToken != null
+                && r.mAppWindowToken.containsDismissKeyguardWindow();
         if (shouldBeVisible) {
             if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
                 mTopDismissingKeyguardActivity = r;
@@ -2561,7 +2562,9 @@
                 final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard
                         && next.canShowWhenLocked();
                 final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next
-                        && next.hasDismissKeyguardWindows();
+                        && next.mAppWindowToken != null
+                        && next.mAppWindowToken.containsDismissKeyguardWindow();
+
                 if (canShowWhenLocked || mayDismissKeyguard) {
                     ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
                             !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0f286ce..d8644df 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.AppProtoEnums;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
@@ -479,4 +480,10 @@
     public abstract void setProfilerInfo(ProfilerInfo profilerInfo);
 
     public abstract ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry();
+
+    /**
+     * Gets bitmap snapshot of the provided task id.
+     */
+    public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId,
+            boolean reducedResolution);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 42121ca..e82e748 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -245,7 +245,7 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -4334,6 +4334,22 @@
     }
 
     @Override
+    public void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                r.setInheritShowWhenLocked(inheritShowWhenLocked);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
     public void setTurnScreenOn(IBinder token, boolean turnScreenOn) {
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInStackLocked(token);
@@ -7012,5 +7028,12 @@
                 return mStackSupervisor.getActivityMetricsLogger().getLaunchObserverRegistry();
             }
         }
+
+        @Override
+        public ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution) {
+            synchronized (mGlobalLock) {
+                return ActivityTaskManagerService.this.getTaskSnapshot(taskId, reducedResolution);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 91aac7e..9b82f5c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2651,28 +2651,6 @@
     }
 
     /**
-     * @return true if the activity contains windows that have
-     *         {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
-     */
-    public boolean containsShowWhenLockedWindow(IBinder token) {
-        synchronized (mGlobalLock) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            return wtoken != null && wtoken.containsShowWhenLockedWindow();
-        }
-    }
-
-    /**
-     * @return true if the activity contains windows that have
-     *         {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set
-     */
-    public boolean containsDismissKeyguardWindow(IBinder token) {
-        synchronized (mGlobalLock) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            return wtoken != null && wtoken.containsDismissKeyguardWindow();
-        }
-    }
-
-    /**
      * Notifies activity manager that some Keyguard flags have changed and that it needs to
      * reevaluate the visibilities of the activities.
      * @param callback Runnable to be called when activity manager is done reevaluating visibilities
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
new file mode 100644
index 0000000..936ee85
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+
+import android.os.Trace;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Buffer used for window tracing.
+ */
+abstract class WindowTraceBuffer {
+    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+    final Object mBufferSizeLock = new Object();
+    final BlockingQueue<byte[]> mBuffer;
+    int mBufferSize;
+    private final int mBufferCapacity;
+    private final File mTraceFile;
+
+    WindowTraceBuffer(int size, File traceFile) throws IOException {
+        mBufferCapacity = size;
+        mTraceFile = traceFile;
+        mBuffer = new LinkedBlockingQueue<>();
+
+        initTraceFile();
+    }
+
+    int getAvailableSpace() {
+        return mBufferCapacity - mBufferSize;
+    }
+
+    /**
+     * Inserts the specified element into this buffer.
+     *
+     * This method is synchronized with {@code #take()} and {@code #clear()}
+     * for consistency.
+     *
+     * @param proto the element to add
+     * @return {@code true} if the inserted item was inserted into the buffer
+     * @throws IllegalStateException if the element cannot be added because it is larger
+     *                               than the buffer size.
+     */
+    boolean add(ProtoOutputStream proto) throws InterruptedException {
+        byte[] protoBytes = proto.getBytes();
+        int protoLength = protoBytes.length;
+        if (protoLength > mBufferCapacity) {
+            throw new IllegalStateException("Trace object too large for the buffer. Buffer size:"
+                    + mBufferCapacity + " Object size: " + protoLength);
+        }
+        synchronized (mBufferSizeLock) {
+            boolean canAdd = canAdd(protoBytes);
+            if (canAdd) {
+                mBuffer.offer(protoBytes);
+                mBufferSize += protoLength;
+            }
+            return canAdd;
+        }
+    }
+
+    void writeNextBufferElementToFile() throws IOException {
+        byte[] proto;
+        try {
+            proto = take();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            return;
+        }
+
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToFile");
+            try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
+                os.write(proto);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element becomes available.
+     *
+     * This method is synchronized with {@code #add(ProtoOutputStream)} and {@code #clear()}
+     * for consistency.
+     *
+     * @return the head of this buffer, or {@code null} if this buffer is empty
+     */
+    private byte[] take() throws InterruptedException {
+        byte[] item = mBuffer.take();
+        synchronized (mBufferSizeLock) {
+            mBufferSize -= item.length;
+            return item;
+        }
+    }
+
+    private void initTraceFile() throws IOException {
+        mTraceFile.delete();
+        try (OutputStream os = new FileOutputStream(mTraceFile)) {
+            mTraceFile.setReadable(true, false);
+            ProtoOutputStream proto = new ProtoOutputStream(os);
+            proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+            proto.flush();
+        }
+    }
+
+    /**
+     * Checks if the element can be added to the buffer. The element is already certain to be
+     * smaller than the overall buffer size.
+     *
+     * @param protoBytes byte array representation of the Proto object to add
+     * @return <tt>true<</tt> if the element can be added to the buffer or not
+     */
+    abstract boolean canAdd(byte[] protoBytes) throws InterruptedException;
+
+    /**
+     * Flush all buffer content to the disk.
+     *
+     * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
+     */
+    abstract void writeToDisk() throws IOException, InterruptedException;
+
+    /**
+     * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceQueueBuffer}
+     */
+    static class Builder {
+        private File mTraceFile;
+        private int mBufferCapacity;
+
+
+        Builder setTraceFile(File traceFile) {
+            mTraceFile = traceFile;
+            return this;
+        }
+
+        Builder setBufferCapacity(int size) {
+            mBufferCapacity = size;
+            return this;
+        }
+
+        File getFile() {
+            return mTraceFile;
+        }
+
+        WindowTraceBuffer build() throws IOException {
+            if (mBufferCapacity <= 0) {
+                throw new IllegalStateException("Buffer capacity must be greater than 0.");
+            }
+
+            if (mTraceFile == null) {
+                throw new IllegalArgumentException("A valid trace file must be specified.");
+            }
+
+            return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
new file mode 100644
index 0000000..b7fc7ac
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.os.Build.IS_USER;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first
+ * {@code #size size} bytes of window trace elements.
+ * Once the buffer is full it will no longer accepts new elements.
+ */
+class WindowTraceQueueBuffer extends WindowTraceBuffer {
+    private Thread mWriterThread;
+    private boolean mCancel;
+
+    @VisibleForTesting
+    WindowTraceQueueBuffer(int size, File traceFile, boolean startWriterThread) throws IOException {
+        super(size, traceFile);
+        if (startWriterThread) {
+            initializeWriterThread();
+        }
+    }
+
+    WindowTraceQueueBuffer(int size, File traceFile) throws IOException {
+        this(size, traceFile, !IS_USER);
+    }
+
+    private void initializeWriterThread() {
+        mCancel = false;
+        mWriterThread = new Thread(() -> {
+            try {
+                loop();
+            } catch (IOException e) {
+                throw new IllegalStateException("Failed to execute trace write loop thread", e);
+            }
+        }, "window_tracing");
+        mWriterThread.start();
+    }
+
+    private void loop() throws IOException {
+        while (!mCancel) {
+            writeNextBufferElementToFile();
+        }
+    }
+
+    private void restartWriterThread() throws InterruptedException {
+        if (mWriterThread != null) {
+            mCancel = true;
+            mWriterThread.interrupt();
+            mWriterThread.join();
+            initializeWriterThread();
+        }
+    }
+
+    @Override
+    boolean canAdd(byte[] protoBytes) {
+        long availableSpace = getAvailableSpace();
+        return availableSpace >= protoBytes.length;
+    }
+
+    @Override
+    void writeToDisk() throws InterruptedException {
+        while (!mBuffer.isEmpty()) {
+            mBufferSizeLock.wait();
+            mBufferSizeLock.notify();
+        }
+        restartWriterThread();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 8fa56bb..63539c4 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -17,31 +17,23 @@
 package com.android.server.wm;
 
 import static android.os.Build.IS_USER;
+
 import static com.android.server.wm.WindowManagerTraceFileProto.ENTRY;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
 import static com.android.server.wm.WindowManagerTraceProto.ELAPSED_REALTIME_NANOS;
 import static com.android.server.wm.WindowManagerTraceProto.WHERE;
 import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.annotation.Nullable;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
 
 /**
  * A class that allows window manager to dump its state continuously to a trace file, such that a
@@ -49,35 +41,42 @@
  */
 class WindowTracing {
 
+    /**
+     * Maximum buffer size, currently defined as 512 KB
+     * Size was experimentally defined to fit between 100 to 150 elements.
+     */
+    private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
     private static final String TAG = "WindowTracing";
-    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
 
     private final Object mLock = new Object();
-    private final File mTraceFile;
-    private final BlockingQueue<ProtoOutputStream> mWriteQueue = new ArrayBlockingQueue<>(200);
+    private final WindowTraceBuffer.Builder mBufferBuilder;
+
+    private WindowTraceBuffer mTraceBuffer;
 
     private boolean mEnabled;
     private volatile boolean mEnabledLockFree;
 
     WindowTracing(File file) {
-        mTraceFile = file;
+        mBufferBuilder = new WindowTraceBuffer.Builder()
+                .setTraceFile(file)
+                .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
     }
 
     void startTrace(@Nullable PrintWriter pw) throws IOException {
-        if (IS_USER){
+        if (IS_USER) {
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
         }
         synchronized (mLock) {
-            logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
-            mWriteQueue.clear();
-            mTraceFile.delete();
-            try (OutputStream os = new FileOutputStream(mTraceFile)) {
-                mTraceFile.setReadable(true, false);
-                ProtoOutputStream proto = new ProtoOutputStream(os);
-                proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
-                proto.flush();
+            logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + ".");
+            if (mTraceBuffer != null) {
+                try {
+                    mTraceBuffer.writeToDisk();
+                } catch (InterruptedException e) {
+                    logAndPrintln(pw, "Error: Unable to flush the previous buffer.");
+                }
             }
+            mTraceBuffer = mBufferBuilder.build();
             mEnabled = mEnabledLockFree = true;
         }
     }
@@ -91,67 +90,42 @@
     }
 
     void stopTrace(@Nullable PrintWriter pw) {
-        if (IS_USER){
+        if (IS_USER) {
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
         }
         synchronized (mLock) {
-            logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
+            logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile()
+                    + ". Waiting for traces to flush.");
             mEnabled = mEnabledLockFree = false;
-            while (!mWriteQueue.isEmpty()) {
+
+            synchronized (mLock) {
                 if (mEnabled) {
                     logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
                     throw new IllegalStateException("tracing enabled while waiting for flush.");
                 }
                 try {
-                    mLock.wait();
-                    mLock.notify();
+                    mTraceBuffer.writeToDisk();
+                } catch (IOException e) {
+                    Log.e(TAG, "Unable to write buffer to file", e);
                 } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
+                    Log.e(TAG, "Unable to interrupt window tracing file write thread", e);
                 }
             }
-            logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
+            logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + ".");
         }
     }
 
-    void appendTraceEntry(ProtoOutputStream proto) {
+    private void appendTraceEntry(ProtoOutputStream proto) {
         if (!mEnabledLockFree) {
             return;
         }
 
-        if (!mWriteQueue.offer(proto)) {
-            Log.e(TAG, "Dropping window trace entry, queue full");
-        }
-    }
-
-    void loop() {
-        for (;;) {
-            loopOnce();
-        }
-    }
-
-    @VisibleForTesting
-    void loopOnce() {
-        ProtoOutputStream proto;
         try {
-            proto = mWriteQueue.take();
+            mTraceBuffer.add(proto);
         } catch (InterruptedException e) {
+            Log.e(TAG, "Unable to add element to trace", e);
             Thread.currentThread().interrupt();
-            return;
-        }
-
-        synchronized (mLock) {
-            try {
-                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToFile");
-                try (OutputStream os = new FileOutputStream(mTraceFile, true /* append */)) {
-                    os.write(proto.getBytes());
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "Failed to write file " + mTraceFile, e);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-            }
-            mLock.notify();
         }
     }
 
@@ -161,11 +135,7 @@
 
     static WindowTracing createDefaultAndStartLooper(Context context) {
         File file = new File("/data/misc/wmtrace/wm_trace.pb");
-        WindowTracing windowTracing = new WindowTracing(file);
-        if (!IS_USER){
-            new Thread(windowTracing::loop, "window_tracing").start();
-        }
-        return windowTracing;
+        return new WindowTracing(file);
     }
 
     int onShellCommand(ShellCommand shell, String cmd) {
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 9ecafb3..c8c5e8f 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -107,6 +107,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.input.classifier@1.0",
         "android.hardware.ir@1.0",
         "android.hardware.light@2.0",
         "android.hardware.power@1.0",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 0929e20..64120076 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -244,7 +244,7 @@
             const sp<IBinder>& token,
             const std::string& reason);
     virtual void notifyInputChannelBroken(const sp<IBinder>& token);
-    virtual void notifyFocusChanged(const sp<IBinder>& token);
+    virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken);
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
@@ -738,7 +738,8 @@
     }
 }
 
-void NativeInputManager::notifyFocusChanged(const sp<IBinder>& token) {
+void NativeInputManager::notifyFocusChanged(const sp<IBinder>& oldToken,
+        const sp<IBinder>& newToken) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     ALOGD("notifyFocusChanged");
 #endif
@@ -746,12 +747,11 @@
 
     JNIEnv* env = jniEnv();
 
-    jobject tokenObj = javaObjectForIBinder(env, token);
-    if (tokenObj) {
-        env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged,
-                tokenObj);
-        checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
-    }
+    jobject oldTokenObj = javaObjectForIBinder(env, oldToken);
+    jobject newTokenObj = javaObjectForIBinder(env, newToken);
+    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged,
+            oldTokenObj, newTokenObj);
+    checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
 }
 
 void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
@@ -1500,27 +1500,6 @@
     im->setSystemUiVisibility(visibility);
 }
 
-static jboolean nativeTransferTouchFocus(JNIEnv* env,
-        jclass /* clazz */, jlong ptr, jobject fromChannelObj, jobject toChannelObj) {
-    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
-
-    sp<InputChannel> fromChannel =
-            android_view_InputChannel_getInputChannel(env, fromChannelObj);
-    sp<InputChannel> toChannel =
-            android_view_InputChannel_getInputChannel(env, toChannelObj);
-
-    if (fromChannel == nullptr || toChannel == nullptr) {
-        return JNI_FALSE;
-    }
-
-    if (im->getInputManager()->getDispatcher()->
-            transferTouchFocus(fromChannel, toChannel)) {
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
 static void nativeSetPointerSpeed(JNIEnv* /* env */,
         jclass /* clazz */, jlong ptr, jint speed) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1708,8 +1687,6 @@
             (void*) nativeSetInputDispatchMode },
     { "nativeSetSystemUiVisibility", "(JI)V",
             (void*) nativeSetSystemUiVisibility },
-    { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z",
-            (void*) nativeTransferTouchFocus },
     { "nativeSetPointerSpeed", "(JI)V",
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(JZ)V",
@@ -1785,7 +1762,7 @@
             "notifyInputChannelBroken", "(Landroid/os/IBinder;)V");
     
     GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz,
-            "notifyFocusChanged", "(Landroid/os/IBinder;)V");
+            "notifyFocusChanged", "(Landroid/os/IBinder;Landroid/os/IBinder;)V");
 
     GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
             "notifyANR",
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 3c87e42..7dd30bd 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -75,6 +75,23 @@
     jbyte* mElements;
 };
 
+int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
+#if HAS_FSVERITY
+    const char* path = env->GetStringUTFChars(filePath, nullptr);
+    ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
+    if (rfd.get() < 0) {
+      return errno;
+    }
+    if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
+      return errno;
+    }
+    return 0;
+#else
+    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+    return ENOSYS;
+#endif  // HAS_FSVERITY
+}
+
 int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
 #if HAS_FSVERITY
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
@@ -82,14 +99,17 @@
     data->digest_size = kSha256Bytes;  // the only input/output parameter
 
     const char* path = env->GetStringUTFChars(filePath, nullptr);
-    ::android::base::unique_fd rfd(open(path, O_RDONLY));
+    ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
+    if (rfd.get() < 0) {
+      return errno;
+    }
     if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
       return errno;
     }
     return 0;
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return -1;
+    return ENOSYS;
 #endif  // HAS_FSVERITY
 }
 
@@ -172,6 +192,7 @@
 }
 
 const JNINativeMethod sMethods[] = {
+    { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity },
     { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
     { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData },
     { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7f6895a..76ae5cc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -221,7 +221,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -245,6 +245,7 @@
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.pm.UserRestrictionsUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -5322,6 +5323,7 @@
         }
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
+        ComponentName adminComponent = null;
         synchronized (getLockObject()) {
             // Make sure the caller has any active admin with the right policy or
             // the required permission.
@@ -5332,8 +5334,7 @@
                     android.Manifest.permission.LOCK_DEVICE);
             final long ident = mInjector.binderClearCallingIdentity();
             try {
-                final ComponentName adminComponent = admin == null ?
-                        null : admin.info.getComponent();
+                adminComponent = admin == null ? null : admin.info.getComponent();
                 if (adminComponent != null) {
                     // For Profile Owners only, callers with only permission not allowed.
                     if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
@@ -5385,6 +5386,7 @@
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.LOCK_NOW)
+                .setAdmin(adminComponent)
                 .setInt(flags)
                 .write();
     }
@@ -6101,7 +6103,9 @@
         synchronized (getLockObject()) {
             delegates = getDelegatePackagesInternalLocked(scope, userId);
         }
-        if (delegates.size() != 1) {
+        if (delegates.size() == 0) {
+            return null;
+        } else if (delegates.size() > 1) {
             Slog.wtf(LOG_TAG, "More than one delegate holds " + scope);
             return null;
         }
@@ -9188,21 +9192,15 @@
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
 
-        // TODO When InputMethodManager supports per user calls remove
-        //      this restriction.
-        if (!checkCallerIsCurrentUserOrProfile()) {
+        // TODO When InputMethodManager supports per user calls remove this restriction.
+        if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
+                && !checkCallerIsCurrentUserOrProfile()) {
             return false;
         }
-
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         if (packageList != null) {
-            // InputMethodManager fetches input methods for current user.
-            // So this can only be set when calling user is the current user
-            // or parent is current user in case of managed profiles.
-            InputMethodManager inputMethodManager =
-                    mContext.getSystemService(InputMethodManager.class);
-            List<InputMethodInfo> enabledImes = inputMethodManager.getEnabledInputMethodList();
-
+            List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
+                    .getEnabledInputMethodListAsUser(callingUserId);
             if (enabledImes != null) {
                 List<String> enabledPackages = new ArrayList<String>();
                 for (InputMethodInfo ime : enabledImes) {
@@ -9250,22 +9248,16 @@
     @Override
     public List getPermittedInputMethodsForCurrentUser() {
         enforceManageUsers();
-        UserInfo currentUser;
-        try {
-            currentUser = mInjector.getIActivityManager().getCurrentUser();
-        } catch (RemoteException e) {
-            Slog.e(LOG_TAG, "Failed to make remote calls to get current user", e);
-            // Activity managed is dead, just allow all IMEs
-            return null;
-        }
 
-        int userId = currentUser.id;
+        final int callingUserId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             List<String> result = null;
             // If we have multiple profiles we return the intersection of the
             // permitted lists. This can happen in cases where we have a device
             // and profile owner.
-            int[] profileIds = mUserManager.getProfileIdsWithDisabled(userId);
+            int[] profileIds = InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
+                    ? new int[]{callingUserId}
+                    : mUserManager.getProfileIdsWithDisabled(callingUserId);
             for (int profileId : profileIds) {
                 // Just loop though all admins, only device or profiles
                 // owners can have permitted lists set.
@@ -9286,9 +9278,8 @@
 
             // If we have a permitted list add all system input methods.
             if (result != null) {
-                InputMethodManager inputMethodManager =
-                        mContext.getSystemService(InputMethodManager.class);
-                List<InputMethodInfo> imes = inputMethodManager.getInputMethodList();
+                List<InputMethodInfo> imes =
+                        InputMethodManagerInternal.get().getInputMethodListAsUser(callingUserId);
                 if (imes != null) {
                     for (InputMethodInfo ime : imes) {
                         ServiceInfo serviceInfo = ime.getServiceInfo();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
index d0ec0ee..699bec2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
@@ -23,6 +23,7 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.admin.DeviceAdminReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -30,15 +31,13 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.util.ArraySet;
 import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.view.IInputMethodManager;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import java.util.Arrays;
 import java.util.List;
@@ -53,18 +52,38 @@
     protected static final String TAG = "OverlayPackagesProvider";
 
     private final PackageManager mPm;
-    private final IInputMethodManager mIInputMethodManager;
     private final Context mContext;
+    private final Injector mInjector;
 
     public OverlayPackagesProvider(Context context) {
-        this(context, getIInputMethodManager());
+        this(context, new DefaultInjector());
     }
 
     @VisibleForTesting
-    OverlayPackagesProvider(Context context, IInputMethodManager iInputMethodManager) {
+    interface Injector {
+        boolean isPerProfileImeEnabled();
+        @NonNull
+        List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
+    }
+
+    private static final class DefaultInjector implements Injector {
+        @Override
+        public boolean isPerProfileImeEnabled() {
+            return InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
+        }
+
+        @NonNull
+        @Override
+        public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
+            return InputMethodManagerInternal.get().getInputMethodListAsUser(userId);
+        }
+    }
+
+    @VisibleForTesting
+    OverlayPackagesProvider(Context context, Injector injector) {
         mContext = context;
         mPm = checkNotNull(context.getPackageManager());
-        mIInputMethodManager = checkNotNull(iInputMethodManager);
+        mInjector = checkNotNull(injector);
     }
 
     /**
@@ -89,10 +108,12 @@
         // Newly installed system apps are uninstalled when they are not required and are either
         // disallowed or have a launcher icon.
         nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
-        // Don't delete the system input method packages in case of Device owner provisioning.
-        if (ACTION_PROVISION_MANAGED_DEVICE.equals(provisioningAction)
+        if (mInjector.isPerProfileImeEnabled()) {
+            nonRequiredApps.removeAll(getSystemInputMethods(userId));
+        } else if (ACTION_PROVISION_MANAGED_DEVICE.equals(provisioningAction)
                 || ACTION_PROVISION_MANAGED_USER.equals(provisioningAction)) {
-            nonRequiredApps.removeAll(getSystemInputMethods());
+            // Don't delete the system input method packages in case of Device owner provisioning.
+            nonRequiredApps.removeAll(getSystemInputMethods(userId));
         }
         nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
         return nonRequiredApps;
@@ -114,16 +135,8 @@
         return apps;
     }
 
-    private Set<String> getSystemInputMethods() {
-        // InputMethodManager is final so it cannot be mocked.
-        // So, we're using IInputMethodManager directly because it can be mocked.
-        final List<InputMethodInfo> inputMethods;
-        try {
-            inputMethods = mIInputMethodManager.getInputMethodList();
-        } catch (RemoteException e) {
-            // Should not happen
-            return null;
-        }
+    private Set<String> getSystemInputMethods(int userId) {
+        final List<InputMethodInfo> inputMethods = mInjector.getInputMethodListAsUser(userId);
         final Set<String> systemInputMethods = new ArraySet<>();
         for (InputMethodInfo inputMethodInfo : inputMethods) {
             ApplicationInfo applicationInfo = inputMethodInfo.getServiceInfo().applicationInfo;
@@ -149,11 +162,6 @@
         return disallowedApps;
     }
 
-    private static IInputMethodManager getIInputMethodManager() {
-        final IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
-        return IInputMethodManager.Stub.asInterface(b);
-    }
-
     private Set<String> getRequiredAppsSet(String provisioningAction) {
         final int resId;
         switch (provisioningAction) {
diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp
new file mode 100644
index 0000000..013cf56
--- /dev/null
+++ b/services/ipmemorystore/Android.bp
@@ -0,0 +1,4 @@
+java_library_static {
+    name: "services.ipmemorystore",
+    srcs: ["java/**/*.java"],
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
new file mode 100644
index 0000000..c9759bf
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
@@ -0,0 +1,151 @@
+/*
+ * 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.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.IIpMemoryStore;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+
+/**
+ * Implementation for the IP memory store.
+ * This component offers specialized services for network components to store and retrieve
+ * knowledge about networks, and provides intelligence that groups level 2 networks together
+ * into level 3 networks.
+ *
+ * @hide
+ */
+public class IpMemoryStoreService extends IIpMemoryStore.Stub {
+    final Context mContext;
+
+    public IpMemoryStoreService(@NonNull final Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Store network attributes for a given L2 key.
+     *
+     * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+     *              key and only care about grouping can pass a unique ID here like the ones
+     *              generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+     *              relevance of such a network will lead to it being evicted soon if it's not
+     *              refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+     * @param attributes The attributes for this network.
+     * @param listener A listener to inform of the completion of this call, or null if the client
+     *        is not interested in learning about success/failure.
+     * Through the listener, returns the L2 key. This is useful if the L2 key was not specified.
+     * If the call failed, the L2 key will be null.
+     */
+    @Override
+    public void storeNetworkAttributes(@NonNull final String l2Key,
+            @NonNull final NetworkAttributesParcelable attributes,
+            @Nullable final IOnStatusListener listener) {
+        // TODO : implement this
+    }
+
+    /**
+     * Store a binary blob associated with an L2 key and a name.
+     *
+     * @param l2Key The L2 key for this network.
+     * @param clientId The ID of the client.
+     * @param name The name of this data.
+     * @param data The data to store.
+     * @param listener The listener that will be invoked to return the answer, or null if the
+     *        is not interested in learning about success/failure.
+     * Through the listener, returns a status to indicate success or failure.
+     */
+    @Override
+    public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
+            @NonNull final String name, @NonNull final Blob data,
+            @Nullable final IOnStatusListener listener) {
+        // TODO : implement this
+    }
+
+    /**
+     * Returns the best L2 key associated with the attributes.
+     *
+     * This will find a record that would be in the same group as the passed attributes. This is
+     * useful to choose the key for storing a sample or private data when the L2 key is not known.
+     * If multiple records are group-close to these attributes, the closest match is returned.
+     * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+     * order) L2 key is returned.
+     * If no record matches these attributes, null is returned.
+     *
+     * @param attributes The attributes of the network to find.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the L2 key if one matched, or null.
+     */
+    @Override
+    public void findL2Key(@NonNull final NetworkAttributesParcelable attributes,
+            @NonNull final IOnL2KeyResponseListener listener) {
+        // TODO : implement this
+    }
+
+    /**
+     * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+     * to the same L3 network. Group-closeness is used to determine this.
+     *
+     * @param l2Key1 The key for the first network.
+     * @param l2Key2 The key for the second network.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, a SameL3NetworkResponse containing the answer and confidence.
+     */
+    @Override
+    public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
+            @NonNull final IOnSameNetworkResponseListener listener) {
+        // TODO : implement this
+    }
+
+    /**
+     * Retrieve the network attributes for a key.
+     * If no record is present for this key, this will return null attributes.
+     *
+     * @param l2Key The key of the network to query.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the network attributes and the L2 key associated with
+     *         the query.
+     */
+    @Override
+    public void retrieveNetworkAttributes(@NonNull final String l2Key,
+            @NonNull final IOnNetworkAttributesRetrieved listener) {
+        // TODO : implement this.
+    }
+
+    /**
+     * Retrieve previously stored private data.
+     * If no data was stored for this L2 key and name this will return null.
+     *
+     * @param l2Key The L2 key.
+     * @param clientId The id of the client that stored this data.
+     * @param name The name of the data.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the private data if any or null if none, with the L2 key
+     *         and the name of the data associated with the query.
+     */
+    @Override
+    public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
+            @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
+        // TODO : implement this.
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4326c39..fef2db9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -102,10 +102,12 @@
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
+import com.android.server.net.ipmemorystore.IpMemoryStoreService;
 import com.android.server.net.watchlist.NetworkWatchlistService;
 import com.android.server.notification.NotificationManagerService;
 import com.android.server.oemlock.OemLockService;
 import com.android.server.om.OverlayManagerService;
+import com.android.server.os.BugreportManagerService;
 import com.android.server.os.DeviceIdentifiersPolicyService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.BackgroundDexOptService;
@@ -118,6 +120,7 @@
 import com.android.server.pm.ShortcutService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.policy.PhoneWindowManager;
+import com.android.server.policy.role.LegacyRoleResolutionPolicy;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.power.ThermalManagerService;
@@ -260,6 +263,10 @@
             "com.android.server.accessibility.AccessibilityManagerService$Lifecycle";
     private static final String ADB_SERVICE_CLASS =
             "com.android.server.adb.AdbService$Lifecycle";
+    private static final String APP_PREDICTION_MANAGER_SERVICE_CLASS =
+            "com.android.server.appprediction.AppPredictionManagerService";
+    private static final String CONTENT_SUGGESTIONS_SERVICE_CLASS =
+            "com.android.server.contentsuggestions.ContentSuggestionsManagerService";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -786,6 +793,11 @@
         traceBeginAndSlog("StartRollbackManagerService");
         mSystemServiceManager.startService(RollbackManagerService.class);
         traceEnd();
+
+        // Service to capture bugreports.
+        traceBeginAndSlog("StartBugreportManagerService");
+        mSystemServiceManager.startService(BugreportManagerService.class);
+        traceEnd();
     }
 
     /**
@@ -1020,6 +1032,18 @@
             Slog.e("System", "************ Failure starting core service", e);
         }
 
+        // Before things start rolling, be sure we have decided whether
+        // we are in safe mode.
+        final boolean safeMode = wm.detectSafeMode();
+        if (safeMode) {
+            // If yes, immediately turn on the global setting for airplane mode.
+            // Note that this does not send broadcasts at this stage because
+            // subsystems are not yet up. We will send broadcasts later to ensure
+            // all listeners have the chance to react with special handling.
+            Settings.Global.putInt(context.getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, 1);
+        }
+
         StatusBarManagerService statusBar = null;
         INotificationManager notification = null;
         LocationManagerService location = null;
@@ -1153,6 +1177,16 @@
 
             startContentCaptureService(context);
 
+            // App prediction manager service
+            traceBeginAndSlog("StartAppPredictionService");
+            mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
+            traceEnd();
+
+            // Content suggestions manager service
+            traceBeginAndSlog("StartContentSuggestionsService");
+            mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
+            traceEnd();
+
             // NOTE: ClipboardService indirectly depends on IntelligenceService
             traceBeginAndSlog("StartClipboardService");
             mSystemServiceManager.startService(ClipboardService.class);
@@ -1167,6 +1201,15 @@
             }
             traceEnd();
 
+            traceBeginAndSlog("StartIpMemoryStoreService");
+            try {
+                ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE,
+                        new IpMemoryStoreService(context));
+            } catch (Throwable e) {
+                reportWtf("starting IP Memory Store Service", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("StartIpSecService");
             try {
                 ipSecService = IpSecService.create(context);
@@ -1786,9 +1829,6 @@
         mSystemServiceManager.startService(StatsCompanionService.Lifecycle.class);
         traceEnd();
 
-        // Before things start rolling, be sure we have decided whether
-        // we are in safe mode.
-        final boolean safeMode = wm.detectSafeMode();
         if (safeMode) {
             traceBeginAndSlog("EnterSafeModeAndDisableJitCompilation");
             mActivityManagerService.enterSafeMode();
@@ -1952,7 +1992,8 @@
 
             // Grants default permissions and defines roles
             traceBeginAndSlog("StartRoleManagerService");
-            mSystemServiceManager.startService(RoleManagerService.class);
+            mSystemServiceManager.startService(new RoleManagerService(
+                    mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
             traceEnd();
 
             // No dependency on Webview preparation in system server. But this should
@@ -1985,6 +2026,20 @@
                 reportWtf("starting System UI", e);
             }
             traceEnd();
+            // Enable airplane mode in safe mode. setAirplaneMode() cannot be called
+            // earlier as it sends broadcasts to other services.
+            // TODO: This may actually be too late if radio firmware already started leaking
+            // RF before the respective services start. However, fixing this requires changes
+            // to radio firmware and interfaces.
+            if (safeMode) {
+                traceBeginAndSlog("EnableAirplaneModeInSafeMode");
+                try {
+                    connectivityF.setAirplaneMode(true);
+                } catch (Throwable e) {
+                    reportWtf("enabling Airplane Mode during Safe Mode bootup", e);
+                }
+                traceEnd();
+            }
             traceBeginAndSlog("MakeNetworkManagementServiceReady");
             try {
                 if (networkManagementF != null) {
@@ -2179,7 +2234,7 @@
         windowManager.onSystemUiStarted();
     }
 
-    private static void traceBeginAndSlog(String name) {
+    private static void traceBeginAndSlog(@NonNull String name) {
         Slog.i(TAG, name);
         BOOT_TIMINGS_TRACE_LOG.traceBegin(name);
     }
diff --git a/services/net/Android.bp b/services/net/Android.bp
index ae697b7..3b4d6a7 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -11,10 +11,10 @@
     ]
 }
 
-// TODO: move to networking module with IpNeighborMonitor/ConnectivityPacketTracker and remove lib
-java_library {
-    name: "frameworks-net-shared-utils",
+filegroup {
+    name: "services-networkstack-shared-srcs",
     srcs: [
-        "java/android/net/util/FdEventsReader.java",
+        "java/android/net/util/FdEventsReader.java", // TODO: move to NetworkStack with IpClient
+        "java/android/net/shared/*.java",
     ]
-}
\ No newline at end of file
+}
diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java
new file mode 100644
index 0000000..463cf2a
--- /dev/null
+++ b/services/net/java/android/net/shared/NetworkMonitorUtils.java
@@ -0,0 +1,66 @@
+/*
+ * 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.net.shared;
+
+import android.content.Context;
+import android.net.NetworkCapabilities;
+import android.provider.Settings;
+
+/** @hide */
+public class NetworkMonitorUtils {
+
+    // Network conditions broadcast constants
+    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
+            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
+    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
+    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
+    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
+    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
+    public static final String EXTRA_CELL_ID = "extra_cellid";
+    public static final String EXTRA_SSID = "extra_ssid";
+    public static final String EXTRA_BSSID = "extra_bssid";
+    /** real time since boot */
+    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
+    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
+    public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
+            "android.permission.ACCESS_NETWORK_CONDITIONS";
+
+    // TODO: once the URL is a resource overlay, remove and have the resource define the default
+    private static final String DEFAULT_HTTP_URL =
+            "http://connectivitycheck.gstatic.com/generate_204";
+
+    /**
+     * Get the captive portal server HTTP URL that is configured on the device.
+     */
+    public static String getCaptivePortalServerHttpUrl(Context context) {
+        final String settingUrl = Settings.Global.getString(
+                context.getContentResolver(),
+                Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+        return settingUrl != null ? settingUrl : DEFAULT_HTTP_URL;
+    }
+
+    /**
+     * Return whether validation is required for a network.
+     * @param dfltNetCap Default requested network capabilities.
+     * @param nc Network capabilities of the network to test.
+     */
+    public static boolean isValidationRequired(
+            NetworkCapabilities dfltNetCap, NetworkCapabilities nc) {
+        // TODO: Consider requiring validation for DUN networks.
+        return dfltNetCap.satisfiedByNetworkCapabilities(nc);
+    }
+}
diff --git a/services/net/java/android/net/shared/PrivateDnsConfig.java b/services/net/java/android/net/shared/PrivateDnsConfig.java
new file mode 100644
index 0000000..41e0bad
--- /dev/null
+++ b/services/net/java/android/net/shared/PrivateDnsConfig.java
@@ -0,0 +1,94 @@
+/*
+ * 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.net.shared;
+
+import android.net.InetAddresses;
+import android.net.PrivateDnsConfigParcel;
+import android.text.TextUtils;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/** @hide */
+public class PrivateDnsConfig {
+    public final boolean useTls;
+    public final String hostname;
+    public final InetAddress[] ips;
+
+    public PrivateDnsConfig() {
+        this(false);
+    }
+
+    public PrivateDnsConfig(boolean useTls) {
+        this.useTls = useTls;
+        this.hostname = "";
+        this.ips = new InetAddress[0];
+    }
+
+    public PrivateDnsConfig(String hostname, InetAddress[] ips) {
+        this.useTls = !TextUtils.isEmpty(hostname);
+        this.hostname = useTls ? hostname : "";
+        this.ips = (ips != null) ? ips : new InetAddress[0];
+    }
+
+    public PrivateDnsConfig(PrivateDnsConfig cfg) {
+        useTls = cfg.useTls;
+        hostname = cfg.hostname;
+        ips = cfg.ips;
+    }
+
+    /**
+     * Indicates whether this is a strict mode private DNS configuration.
+     */
+    public boolean inStrictMode() {
+        return useTls && !TextUtils.isEmpty(hostname);
+    }
+
+    @Override
+    public String toString() {
+        return PrivateDnsConfig.class.getSimpleName()
+                + "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
+    }
+
+    /**
+     * Create a stable AIDL-compatible parcel from the current instance.
+     */
+    public PrivateDnsConfigParcel toParcel() {
+        final PrivateDnsConfigParcel parcel = new PrivateDnsConfigParcel();
+        parcel.hostname = hostname;
+
+        final String[] parceledIps = new String[ips.length];
+        for (int i = 0; i < ips.length; i++) {
+            parceledIps[i] = ips[i].getHostAddress();
+        }
+        parcel.ips = parceledIps;
+
+        return parcel;
+    }
+
+    /**
+     * Build a configuration from a stable AIDL-compatible parcel.
+     */
+    public static PrivateDnsConfig fromParcel(PrivateDnsConfigParcel parcel) {
+        final InetAddress[] ips = new InetAddress[parcel.ips.length];
+        for (int i = 0; i < ips.length; i++) {
+            ips[i] = InetAddresses.parseNumericAddress(parcel.ips[i]);
+        }
+
+        return new PrivateDnsConfig(parcel.hostname, ips);
+    }
+}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index 8b7b59d..2cdb2b0 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -70,6 +70,10 @@
         mComponent = component;
     }
 
+    public String getTag() {
+        return mTag;
+    }
+
     /**
      * Create a SharedLog based on this log with an additional component prefix on each logged line.
      */
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 5e84ab0..7dac795 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -71,6 +71,7 @@
 
 import android.annotation.Nullable;
 import android.app.Application;
+import android.app.ApplicationPackageManager;
 import android.app.IBackupAgent;
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
@@ -134,6 +135,8 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
 import org.robolectric.shadows.ShadowLooper;
 import org.robolectric.shadows.ShadowPackageManager;
 import org.robolectric.shadows.ShadowQueuedWork;
@@ -157,6 +160,7 @@
 @Config(
         shadows = {
             FrameworkShadowLooper.class,
+            KeyValueBackupTaskTest.ShadowApplicationPackageManager.class,
             ShadowBackupDataInput.class,
             ShadowBackupDataOutput.class,
             ShadowEventLog.class,
@@ -244,6 +248,7 @@
     @After
     public void tearDown() throws Exception {
         ShadowBackupDataInput.reset();
+        ShadowApplicationPackageManager.reset();
     }
 
     @Test
@@ -2435,7 +2440,8 @@
             mPackageManager.setApplicationEnabledSetting(
                     packageData.packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
             PackageInfo packageInfo = getPackageInfo(packageData);
-            mShadowPackageManager.addPackage(packageInfo);
+            mShadowPackageManager.installPackage(packageInfo);
+            ShadowApplicationPackageManager.setPackageInfo(packageInfo);
             mContext.sendBroadcast(getPackageAddedIntent(packageData));
             // Run the backup looper because on the receiver we post MSG_SCHEDULE_BACKUP_PACKAGE
             mShadowBackupLooper.runToEndOfTasks();
@@ -2848,4 +2854,29 @@
             throw mException;
         }
     }
+
+    /**
+     * Extends {@link org.robolectric.shadows.ShadowApplicationPackageManager} to return the correct
+     * package in user-specific invocations.
+     */
+    @Implements(value = ApplicationPackageManager.class)
+    public static class ShadowApplicationPackageManager
+            extends org.robolectric.shadows.ShadowApplicationPackageManager {
+        private static PackageInfo sPackageInfo;
+
+        static void setPackageInfo(PackageInfo packageInfo) {
+            sPackageInfo = packageInfo;
+        }
+
+        @Override
+        protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) {
+            return sPackageInfo;
+        }
+
+        /** Clear {@link #sPackageInfo}. */
+        @Resetter
+        public static void reset() {
+            sPackageInfo = null;
+        }
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 148faad..6a153d5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -60,6 +60,7 @@
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.SparseArray;
@@ -81,6 +82,7 @@
 
 import java.util.ArrayList;
 
+@Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AlarmManagerServiceTest {
diff --git a/services/tests/rescueparty/Android.bp b/services/tests/rescueparty/Android.bp
new file mode 100644
index 0000000..6733af4
--- /dev/null
+++ b/services/tests/rescueparty/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2008 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.
+
+cc_test {
+    name: "log_rescueparty_reset_event_reported",
+    srcs: ["log_rescueparty_reset_event_reported.cpp"],
+    shared_libs: [
+        "libbase",
+        "libstatslog",
+    ],
+    gtest: false,
+}
diff --git a/services/tests/rescueparty/how_to_run.txt b/services/tests/rescueparty/how_to_run.txt
new file mode 100644
index 0000000..9528d39
--- /dev/null
+++ b/services/tests/rescueparty/how_to_run.txt
@@ -0,0 +1,9 @@
+# Per http://go/westworld-local-development#step3-test-atom-and-metric-locally-on-device ,
+# In one terminal:
+make statsd_testdrive
+./out/host/linux-x86/bin/statsd_testdrive 122
+
+# In another terminal:
+mma -j $(nproc) log_rescueparty_reset_event_reported
+adb push $OUT/testcases/log_rescueparty_reset_event_reported/arm64/log_rescueparty_reset_event_reported /data
+adb shell /data/log_rescueparty_reset_event_reported 1234
diff --git a/services/tests/rescueparty/log_rescueparty_reset_event_reported.cpp b/services/tests/rescueparty/log_rescueparty_reset_event_reported.cpp
new file mode 100644
index 0000000..4aea917
--- /dev/null
+++ b/services/tests/rescueparty/log_rescueparty_reset_event_reported.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2008 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.
+
+#include <statslog.h>
+#include <cstdlib>
+
+int main(int argc, const char** argv) {
+    int level = 0;
+    if (argc > 1) {
+        level = std::atoi(argv[1]);
+    }
+    android::util::stats_write(android::util::RESCUE_PARTY_RESET_REPORTED, level);
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 6a10ff4..2cc338c 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -70,7 +70,7 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
 import com.android.server.am.ProcessList.IsolatedUidRange;
 import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
 import com.android.server.wm.ActivityTaskManagerService;
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 05cb48b..8109b1c 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -25,7 +25,7 @@
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index 9626990..cbdc6c3 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -34,7 +34,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
 
 import org.junit.AfterClass;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
index 7e0dfcf..65c5781 100644
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.appops;
+package com.android.server.appop;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 4ae9bea..36f84d0 100644
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.server;
+package com.android.server.appop;
 
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_ERRORED;
@@ -36,6 +36,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.appop.AppOpsService;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index aac96a1d..eb0c627 100644
--- a/services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.appop;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
index 34edd9f..757a046 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
@@ -32,7 +32,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
-import android.os.RemoteException;
 import android.test.AndroidTestCase;
 import android.test.mock.MockPackageManager;
 import android.view.inputmethod.InputMethodInfo;
@@ -40,7 +39,6 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.R;
-import com.android.internal.view.IInputMethodManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,8 +59,8 @@
 
     private @Mock
     Resources mResources;
-    private @Mock
-    IInputMethodManager mIInputMethodManager;
+    @Mock
+    private OverlayPackagesProvider.Injector mInjector;
     private @Mock
     Context mTestContext;
     private Resources mRealResources;
@@ -81,6 +79,7 @@
                 InstrumentationRegistry.getTargetContext().getCacheDir());
 
         setSystemInputMethods();
+        setIsPerProfileModeEnabled(false);
         setRequiredAppsManagedDevice();
         setVendorRequiredAppsManagedDevice();
         setDisallowedAppsManagedDevice();
@@ -95,7 +94,7 @@
         setVendorDisallowedAppsManagedUser();
 
         mRealResources = InstrumentationRegistry.getTargetContext().getResources();
-        mHelper = new OverlayPackagesProvider(mTestContext, mIInputMethodManager);
+        mHelper = new OverlayPackagesProvider(mTestContext, mInjector);
     }
 
     @Test
@@ -165,6 +164,15 @@
     }
 
     @Test
+    public void testProfileOwnerImesAreRequiredForPerProfileImeMode() {
+        setSystemAppsWithLauncher("app.a", "app.b");
+        setSystemInputMethods("app.a");
+        setIsPerProfileModeEnabled(true);
+
+        verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.b");
+    }
+
+    @Test
     public void testManagedUserImesAreRequired() {
         setSystemAppsWithLauncher("app.a", "app.b");
         setSystemInputMethods("app.a");
@@ -333,11 +341,11 @@
             InputMethodInfo inputMethodInfo = new InputMethodInfo(ri, false, null, null, 0, false);
             inputMethods.add(inputMethodInfo);
         }
-        try {
-            when(mIInputMethodManager.getInputMethodList()).thenReturn(inputMethods);
-        } catch (RemoteException e) {
-            fail(e.toString());
-        }
+        when(mInjector.getInputMethodListAsUser(eq(TEST_USER_ID))).thenReturn(inputMethods);
+    }
+
+    private void setIsPerProfileModeEnabled(boolean enabled) {
+        when(mInjector.isPerProfileImeEnabled()).thenReturn(enabled);
     }
 
     private void setSystemAppsWithLauncher(String... apps) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
new file mode 100644
index 0000000..8b0e8ab
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.hdmi;
+
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.Nullable;
+import android.app.Instrumentation;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.Looper;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+
+/** Tests for {@link ArcInitiationActionFromAvrTest} */
+@SmallTest
+@RunWith(JUnit4.class)
+public class ArcInitiationActionFromAvrTest {
+
+    private HdmiDeviceInfo mDeviceInfoForTests;
+    private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+    private HdmiCecController mHdmiCecController;
+    private HdmiControlService mHdmiControlService;
+    private FakeNativeWrapper mNativeWrapper;
+    private ArcInitiationActionFromAvr mAction;
+
+    private TestLooper mTestLooper = new TestLooper();
+    private boolean mSendCecCommandSuccess;
+    private boolean mShouldDispatchARCInitiated;
+    private boolean mArcInitSent;
+    private boolean mRequestActiveSourceSent;
+    private Instrumentation mInstrumentation;
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        mDeviceInfoForTests = new HdmiDeviceInfo(1000, 1);
+
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+        mHdmiControlService =
+                new HdmiControlService(mInstrumentation.getTargetContext()) {
+                    @Override
+                    void sendCecCommand(
+                            HdmiCecMessage command, @Nullable SendMessageCallback callback) {
+                        switch (command.getOpcode()) {
+                            case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE:
+                                if (callback != null) {
+                                    callback.onSendCompleted(
+                                            mSendCecCommandSuccess
+                                                    ? SendMessageResult.SUCCESS
+                                                    : SendMessageResult.NACK);
+                                }
+                                mRequestActiveSourceSent = true;
+                                break;
+                            case Constants.MESSAGE_INITIATE_ARC:
+                                if (callback != null) {
+                                    callback.onSendCompleted(
+                                            mSendCecCommandSuccess
+                                                    ? SendMessageResult.SUCCESS
+                                                    : SendMessageResult.NACK);
+                                }
+                                mArcInitSent = true;
+                                if (mShouldDispatchARCInitiated) {
+                                    mHdmiCecLocalDeviceAudioSystem.dispatchMessage(
+                                            HdmiCecMessageBuilder.buildReportArcInitiated(
+                                                    Constants.ADDR_TV,
+                                                    Constants.ADDR_AUDIO_SYSTEM));
+                                }
+                                break;
+                            default:
+                        }
+                    }
+
+                    @Override
+                    boolean isPowerStandby() {
+                        return false;
+                    }
+
+                    @Override
+                    boolean isAddressAllocated() {
+                        return true;
+                    }
+
+                    @Override
+                    Looper getServiceLooper() {
+                        return mTestLooper.getLooper();
+                    }
+                };
+
+        mHdmiCecLocalDeviceAudioSystem =
+                new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+                    @Override
+                    HdmiDeviceInfo getDeviceInfo() {
+                        return mDeviceInfoForTests;
+                    }
+
+                    @Override
+                    void setArcStatus(boolean enabled) {
+                        // do nothing
+                    }
+
+                    @Override
+                    protected boolean isSystemAudioActivated() {
+                        return true;
+                    }
+                };
+
+        mHdmiCecLocalDeviceAudioSystem.init();
+        Looper looper = mTestLooper.getLooper();
+        mHdmiControlService.setIoLooper(looper);
+        mNativeWrapper = new FakeNativeWrapper();
+        mHdmiCecController =
+                HdmiCecController.createWithNativeWrapper(this.mHdmiControlService, mNativeWrapper);
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mHdmiControlService.initPortInfo();
+        mAction = new ArcInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
+
+        mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void arcInitiation_requestActiveSource() {
+        mSendCecCommandSuccess = true;
+        mShouldDispatchARCInitiated = true;
+        mRequestActiveSourceSent = false;
+        mArcInitSent = false;
+
+        mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+        mTestLooper.dispatchAll();
+
+        assertThat(mArcInitSent).isTrue();
+        assertThat(mRequestActiveSourceSent).isTrue();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index da840be..93a09dc 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -18,6 +18,7 @@
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
@@ -25,16 +26,21 @@
 import static com.android.server.hdmi.Constants.ADDR_SPECIFIC_USE;
 import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+
 import static junit.framework.Assert.assertEquals;
 
 import android.content.Context;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Looper;
 import android.os.test.TestLooper;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
+
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -136,6 +142,7 @@
         assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
     }
 
+    @Ignore("b/110413065 Support multiple device types 4 and 5.")
     @Test
     public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
         mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
@@ -151,6 +158,7 @@
         assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
     }
 
+    @Ignore("b/110413065 Support multiple device types 4 and 5.")
     @Test
     public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
         mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index bdede33..b47f269 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -17,6 +17,8 @@
 
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
 import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
@@ -34,6 +36,7 @@
 import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -52,6 +55,7 @@
     private HdmiControlService mHdmiControlService;
     private HdmiCecController mHdmiCecController;
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
     private FakeNativeWrapper mNativeWrapper;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
@@ -64,82 +68,86 @@
     @Before
     public void setUp() {
         mHdmiControlService =
-                new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
-                    @Override
-                    AudioManager getAudioManager() {
-                        return new AudioManager() {
-                            @Override
-                            public int getStreamVolume(int streamType) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        return mMusicVolume;
-                                    default:
-                                        return 0;
-                                }
+            new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                @Override
+                AudioManager getAudioManager() {
+                    return new AudioManager() {
+                        @Override
+                        public int getStreamVolume(int streamType) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    return mMusicVolume;
+                                default:
+                                    return 0;
                             }
+                        }
 
-                            @Override
-                            public boolean isStreamMute(int streamType) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        return mMusicMute;
-                                    default:
-                                        return false;
-                                }
+                        @Override
+                        public boolean isStreamMute(int streamType) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    return mMusicMute;
+                                default:
+                                    return false;
                             }
+                        }
 
-                            @Override
-                            public int getStreamMaxVolume(int streamType) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        return mMusicMaxVolume;
-                                    default:
-                                        return 100;
-                                }
+                        @Override
+                        public int getStreamMaxVolume(int streamType) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    return mMusicMaxVolume;
+                                default:
+                                    return 100;
                             }
+                        }
 
-                            @Override
-                            public void adjustStreamVolume(
-                                    int streamType, int direction, int flags) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        if (direction == AudioManager.ADJUST_UNMUTE) {
-                                            mMusicMute = false;
-                                        } else if (direction == AudioManager.ADJUST_MUTE) {
-                                            mMusicMute = true;
-                                        }
-                                    default:
-                                }
+                        @Override
+                        public void adjustStreamVolume(
+                                int streamType, int direction, int flags) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    if (direction == AudioManager.ADJUST_UNMUTE) {
+                                        mMusicMute = false;
+                                    } else if (direction == AudioManager.ADJUST_MUTE) {
+                                        mMusicMute = true;
+                                    }
+                                    break;
+                                default:
                             }
+                        }
 
-                            @Override
-                            public void setWiredDeviceConnectionState(
-                                    int type, int state, String address, String name) {
-                                // Do nothing.
-                            }
-                        };
-                    }
+                        @Override
+                        public void setWiredDeviceConnectionState(
+                                int type, int state, String address, String name) {
+                            // Do nothing.
+                        }
+                    };
+                }
 
-                    @Override
-                    void wakeUp() {}
-
-                    @Override
-                    boolean isControlEnabled() {
-                        return true;
-                    }
-                };
+                @Override
+                void wakeUp() {}
+            };
 
         mMyLooper = mTestLooper.getLooper();
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
+            @Override
+            void setIsActiveSource(boolean on) {
+                mIsActiveSource = on;
+            }
+        };
         mHdmiCecLocalDeviceAudioSystem.init();
+        mHdmiCecLocalDevicePlayback.init();
         mHdmiControlService.setIoLooper(mMyLooper);
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController =
-                HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
+            HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
         mHdmiControlService.setCecController(mHdmiCecController);
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
         mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
         mHdmiControlService.initPortInfo();
         // No TV device interacts with AVR so system audio control won't be turned on here
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
@@ -170,11 +178,12 @@
     @Test
     public void handleGiveSystemAudioModeStatus_originalOff() throws Exception {
         HdmiCecMessage expectedMessage =
-                HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
+                HdmiCecMessageBuilder.buildReportSystemAudioMode(
+                        ADDR_AUDIO_SYSTEM, ADDR_TV, false);
         HdmiCecMessage messageGive =
                 HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
@@ -190,9 +199,9 @@
 
         mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
-                                MESSAGE_REQUEST_SAD_LCPM))
-                .isTrue();
+            mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
+                MESSAGE_REQUEST_SAD_LCPM))
+            .isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
@@ -206,11 +215,11 @@
                         Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
                         Constants.ABORT_NOT_IN_CORRECT_MODE);
 
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
-                                MESSAGE_REQUEST_SAD_LCPM))
-                .isEqualTo(true);
+            mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
+                MESSAGE_REQUEST_SAD_LCPM))
+            .isEqualTo(true);
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
@@ -224,11 +233,11 @@
                         Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
                         Constants.ABORT_UNABLE_TO_DETERMINE);
 
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
-                                MESSAGE_REQUEST_SAD_LCPM))
-                .isEqualTo(true);
+            mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
+                MESSAGE_REQUEST_SAD_LCPM))
+            .isEqualTo(true);
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
@@ -244,17 +253,17 @@
         HdmiCecMessage expectedMessage =
                 HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
         // Check if correctly turned on
         mNativeWrapper.clearResultMessages();
         expectedMessage =
-                HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);
+            HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
         assertThat(mMusicMute).isFalse();
@@ -273,15 +282,15 @@
                 HdmiCecMessageBuilder.buildSetSystemAudioMode(
                         ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOff))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
 
         mNativeWrapper.clearResultMessages();
         expectedMessage =
-                HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
+            HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
         assertThat(mMusicMute).isTrue();
@@ -289,10 +298,8 @@
 
     @Test
     public void onStandbyAudioSystem_currentSystemAudioControlOn() throws Exception {
-        mHdmiCecLocalDeviceAudioSystem.setAutoDeviceOff(false);
-        mHdmiCecLocalDeviceAudioSystem.setAutoTvOff(false);
         // Set system audio control on first
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true);
         // Check if standby correctly turns off the feature
         mHdmiCecLocalDeviceAudioSystem.onStandby(false, STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
@@ -309,9 +316,9 @@
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isNotEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isNotEmpty();
     }
 
     @Test
@@ -320,9 +327,9 @@
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isEmpty();
     }
 
     @Test
@@ -331,9 +338,9 @@
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isEmpty();
     }
 
     @Test
@@ -342,9 +349,9 @@
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isNotEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isNotEmpty();
     }
 
     @Test
@@ -354,12 +361,12 @@
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().equals(expectedActiveSource))
-                .isTrue();
+            .isTrue();
     }
 
     @Test
     public void terminateSystemAudioMode_systemAudioModeOff() throws Exception {
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse();
         mMusicMute = false;
         HdmiCecMessage message =
@@ -373,7 +380,7 @@
 
     @Test
     public void terminateSystemAudioMode_systemAudioModeOn() throws Exception {
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true);
         assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
         mMusicMute = false;
         HdmiCecMessage expectedMessage =
@@ -458,7 +465,7 @@
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcInitiationActionFromAvr.class))
-                .isNotEmpty();
+            .isNotEmpty();
     }
 
     @Test
@@ -473,7 +480,7 @@
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcTerminationActionFromAvr.class))
-                .isNotEmpty();
+            .isNotEmpty();
     }
 
     @Test
@@ -510,23 +517,98 @@
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
-    @Test
-    public void onStandby_setAutoDeviceOff_true() throws Exception {
+    public void handleSystemAudioModeRequest_fromNonTV_tVNotSupport() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+                        ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
+                        mAvrPhysicalAddress, true);
         HdmiCecMessage expectedMessage =
-                HdmiCecMessageBuilder.buildStandby(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST);
-        mHdmiCecLocalDeviceAudioSystem.setAutoDeviceOff(true);
-        mHdmiCecLocalDeviceAudioSystem.onStandby(false, STANDBY_SCREEN_OFF);
+                HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                        ADDR_AUDIO_SYSTEM,
+                        ADDR_TUNER_1,
+                        Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
+                        Constants.ABORT_REFUSED);
 
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
-    public void handleSetStreamPath_underCurrentDevice() {
-        assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(0);
+    public void handleSystemAudioModeRequest_fromNonTV_tVSupport() {
         HdmiCecMessage message =
-                HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetStreamPath(message)).isTrue();
-        assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(1);
+                HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+                        ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
+                        mAvrPhysicalAddress, true);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildSetSystemAudioMode(
+                        ADDR_AUDIO_SYSTEM, Constants.ADDR_BROADCAST, true);
+        mHdmiCecLocalDeviceAudioSystem.setTvSystemAudioModeSupport(true);
+
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+    }
+
+    @Test
+    public void handleActiveSource_activeSourceFromTV_swithToArc() {
+        mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+
+        ActiveSource expectedActiveSource = ActiveSource.of(ADDR_TV, 0x0000);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource())
+            .isEqualTo(expectedActiveSource);
+    }
+
+    @Ignore("b/110413065 Support multiple device types 4 and 5.")
+    @Test
+    public void handleRoutingChange_currentActivePortIsHome() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, mAvrPhysicalAddress);
+
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
+        ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
+        int expectedLocalActivePort = Constants.CEC_SWITCH_HOME;
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource())
+            .isEqualTo(expectedActiveSource);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getRoutingPort())
+            .isEqualTo(expectedLocalActivePort);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+    }
+
+    @Test
+    public void handleRoutingInformation_currentActivePortIsHDMI1() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x2000);
+        mHdmiCecLocalDeviceAudioSystem.setRoutingPort(Constants.CEC_SWITCH_HDMI1);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_AUDIO_SYSTEM, 0x2100);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingInformation(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+    }
+
+    @Ignore("b/110413065 Support multiple device types 4 and 5.")
+    @Test
+    public void handleRoutingChange_homeIsActive_playbackSendActiveSource() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x2000);
+
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, 0x2000);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
new file mode 100644
index 0000000..792c617
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.hdmi;
+
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Looper;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiCecLocalDevicePlayback} class. */
+public class HdmiCecLocalDevicePlaybackTest {
+
+    private HdmiControlService mHdmiControlService;
+    private HdmiCecController mHdmiCecController;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
+    private FakeNativeWrapper mNativeWrapper;
+    private Looper mMyLooper;
+    private TestLooper mTestLooper = new TestLooper();
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+    private int mPlaybackPhysicalAddress;
+
+    @Before
+    public void setUp() {
+        mHdmiControlService =
+            new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                @Override
+                void wakeUp() {
+                }
+
+                @Override
+                boolean isControlEnabled() {
+                    return true;
+                }
+            };
+
+        mMyLooper = mTestLooper.getLooper();
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService);
+        mHdmiCecLocalDevicePlayback.init();
+        mHdmiControlService.setIoLooper(mMyLooper);
+        mNativeWrapper = new FakeNativeWrapper();
+        mHdmiCecController =
+            HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+        mHdmiControlService.initPortInfo();
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
+        mPlaybackPhysicalAddress = 0x2000;
+        mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
+    }
+
+    @Ignore
+    @Test
+    public void handleSetStreamPath_underCurrentDevice() {
+        assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100);
+        assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
+        // TODO(amyjojo): Move set and get LocalActivePath to Control Service.
+        assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(1);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
index c7809d3..ef974f2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
@@ -18,6 +18,7 @@
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
 import static com.android.server.hdmi.Constants.ADDR_TV;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
@@ -51,6 +52,14 @@
         assertThat(message).isEqualTo(buildMessage("05:A4:06:01"));
     }
 
+    @Test
+    public void buildRoutingInformation() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingInformation(
+                        ADDR_AUDIO_SYSTEM, 0x2100);
+        assertThat(message).isEqualTo(buildMessage("5F:81:21:00"));
+    }
+
     /**
      * Build a CEC message from a hex byte string with bytes separated by {@code :}.
      *
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index d914b9a..bd297ee 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -26,8 +26,10 @@
 import android.media.AudioManager;
 import android.os.Looper;
 import android.os.test.TestLooper;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,6 +51,9 @@
     private int mMsgRequestActiveSourceCount;
     private int mMsgSetSystemAudioModeCount;
     private int mQueryTvSystemAudioModeSupportCount;
+    private boolean mArcEnabled;
+    private boolean mIsPlaybackDevice;
+    private boolean mBroadcastActiveSource;
 
     @Before
     public void SetUp() {
@@ -80,6 +85,8 @@
                                     callback.onSendCompleted(SendMessageResult.NACK);
                                 }
                                 break;
+                            case Constants.MESSAGE_INITIATE_ARC:
+                                break;
                             default:
                                 throw new IllegalArgumentException("Unexpected message");
                         }
@@ -132,6 +139,17 @@
                     int getPhysicalAddress() {
                         return 0;
                     }
+
+                    @Override
+                    boolean isPlaybackDevice() {
+                        return mIsPlaybackDevice;
+                    }
+
+                    @Override
+                    public void setAndBroadcastActiveSourceFromOneDeviceType(
+                            int sourceAddress, int physicalAddress) {
+                        mBroadcastActiveSource = true;
+                    }
                 };
         mHdmiCecLocalDeviceAudioSystem =
                 new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -148,6 +166,11 @@
                     HdmiDeviceInfo getDeviceInfo() {
                         return mDeviceInfoForTests;
                     }
+
+                    @Override
+                    void setArcStatus(boolean enabled) {
+                        mArcEnabled = enabled;
+                    }
                 };
         mHdmiCecLocalDeviceAudioSystem.init();
         Looper looper = mTestLooper.getLooper();
@@ -159,7 +182,7 @@
         resetTestVariables();
         mShouldDispatchActiveSource = false;
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
                 .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
 
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
@@ -171,7 +194,7 @@
         assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(0);
         assertFalse(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
                 .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
     }
 
@@ -206,14 +229,15 @@
         assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
         assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress).isEqualTo(1002);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
+            .isEqualTo(1002);
     }
 
     @Test
     public void testKnownActiveSource() {
         resetTestVariables();
         mTvSystemAudioModeSupport = true;
-        mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress = 1001;
+        mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress = 1001;
 
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
                 new SystemAudioInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem));
@@ -233,7 +257,7 @@
         mTryCountBeforeSucceed = 3;
         assertThat(mTryCountBeforeSucceed)
                 .isAtMost(SystemAudioInitiationActionFromAvr.MAX_RETRY_COUNT);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
                 .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
 
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
@@ -246,12 +270,32 @@
         assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
     }
 
+    @Test
+    public void testIsPlaybackDevice_cannotReceiveActiveSource() {
+        resetTestVariables();
+        mIsPlaybackDevice = true;
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
+            .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
+
+        mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
+                new SystemAudioInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem));
+        mTestLooper.dispatchAll();
+
+        assertThat(mMsgRequestActiveSourceCount).isEqualTo(1);
+        assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
+        assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
+        assertThat(mBroadcastActiveSource).isTrue();
+    }
+
     private void resetTestVariables() {
         mMsgRequestActiveSourceCount = 0;
         mMsgSetSystemAudioModeCount = 0;
         mQueryTvSystemAudioModeSupportCount = 0;
         mTryCountBeforeSucceed = 0;
-        mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress =
+        mIsPlaybackDevice = false;
+        mBroadcastActiveSource = false;
+        mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress =
                 Constants.INVALID_PHYSICAL_ADDRESS;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 561c61f..0dff03f 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -47,6 +47,7 @@
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.PowerManagerService.Injector;
 import com.android.server.power.PowerManagerService.NativeWrapper;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
 import com.android.server.power.batterysaver.BatterySavingStats;
 
 import org.junit.Rule;
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
similarity index 94%
rename from services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
rename to services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index acf511e..73eefcf 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.server.power;
+package com.android.server.power.batterysaver;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -31,13 +31,12 @@
 import com.android.frameworks.servicestests.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
-import com.android.server.power.batterysaver.BatterySavingStats;
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 /**
- * Tests for {@link com.android.server.power.BatterySaverPolicy}
+ * Tests for {@link com.android.server.power.batterysaver.BatterySaverPolicy}
  */
 public class BatterySaverPolicyTest extends AndroidTestCase {
     private static final boolean BATTERY_SAVER_ON = true;
@@ -62,7 +61,7 @@
     private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
 
     private class BatterySaverPolicyForTest extends BatterySaverPolicy {
-        public BatterySaverPolicyForTest(Object lock, Context context,
+        BatterySaverPolicyForTest(Object lock, Context context,
                 BatterySavingStats batterySavingStats) {
             super(lock, context, batterySavingStats);
         }
@@ -269,15 +268,15 @@
         mBatterySaverPolicy.onChange();
         assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
         assertThat(mBatterySaverPolicy.getFileValues(false).toString())
-                .isEqualTo("{/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq=123, " +
-                "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=456}");
+                .isEqualTo("{/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq=123, "
+                        + "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=456}");
 
         mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_3;
 
         mBatterySaverPolicy.onChange();
         assertThat(mBatterySaverPolicy.getFileValues(true).toString())
-                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=333, " +
-                        "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=444}");
+                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=333, "
+                        + "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=444}");
         assertThat(mBatterySaverPolicy.getFileValues(false).toString())
                 .isEqualTo("{/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=222}");
 
@@ -287,9 +286,9 @@
 
         mBatterySaverPolicy.onChange();
         assertThat(mBatterySaverPolicy.getFileValues(true).toString())
-                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=1234567890, " +
-                        "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=14, " +
-                        "/sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq=15}");
+                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=1234567890, "
+                        + "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=14, "
+                        + "/sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq=15}");
         assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
     }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 1458266..b9ae7d5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -56,8 +56,8 @@
 import android.provider.Settings;
 import android.service.notification.Adjustment;
 import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.R;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -87,14 +87,7 @@
     private final String channelId = "channel";
     private NotificationChannel channel =
             new NotificationChannel(channelId, "test", NotificationManager.IMPORTANCE_DEFAULT);
-    private final String channelIdLong =
-            "give_a_developer_a_string_argument_and_who_knows_what_they_will_pass_in_there";
     private final String groupId = "group";
-    private final String groupIdOverride = "other_group";
-    private final String groupIdLong =
-            "0|com.foo.bar|g:content://com.foo.bar.ui/account%3A-0000000/account/";
-    private NotificationChannel channelLongId =
-            new NotificationChannel(channelIdLong, "long", NotificationManager.IMPORTANCE_DEFAULT);
     private NotificationChannel defaultChannel =
             new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
                     NotificationManager.IMPORTANCE_UNSPECIFIED);
@@ -408,73 +401,27 @@
     }
 
     @Test
-    public void testLogmakerShortChannel() {
+    public void testLogMaker() {
+        long timestamp = 1000L;
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        final LogMaker logMaker = record.getLogMaker();
+        final LogMaker logMaker = record.getLogMaker(timestamp);
+
+        assertNull(logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX));
         assertEquals(channelId,
                 (String) logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID));
         assertEquals(channel.getImportance(),
                 logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE));
-    }
-
-    @Test
-    public void testLogmakerLongChannel() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-        true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-        false /* lights */, false /*defaultLights */, null /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channelLongId);
-        final String loggedId = (String)
-            record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID);
-        assertEquals(channelIdLong.substring(0,10), loggedId.substring(0, 10));
-    }
-
-    @Test
-    public void testLogmakerNoGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /*defaultLights */, null /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        assertNull(record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-    }
-
-    @Test
-    public void testLogmakerShortGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /* defaultLights */, groupId /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        assertEquals(groupId,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-    }
-
-    @Test
-    public void testLogmakerLongGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /* defaultLights */, groupIdLong /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        final String loggedId = (String)
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID);
-        assertEquals(groupIdLong.substring(0,10), loggedId.substring(0, 10));
-    }
-
-    @Test
-    public void testLogmakerOverrideGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /* defaultLights */, groupId /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        assertEquals(groupId,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-        record.setOverrideGroupKey(groupIdOverride);
-        assertEquals(groupIdOverride,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-        record.setOverrideGroupKey(null);
-        assertEquals(groupId,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+        assertEquals(record.getLifespanMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
+        assertEquals(record.getFreshnessMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
+        assertEquals(record.getExposureMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
+        assertEquals(record.getInterruptionMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS));
     }
 
     @Test
@@ -845,4 +792,52 @@
 
         assertFalse(record.isNewEnoughForAlerting(record.mUpdateTimeMs + (1000 * 60 * 60)));
     }
+
+    @Test
+    public void testIgnoreImportanceAdjustmentsForOemLockedChannels() {
+        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+        channel.setImportanceLockedByOEM(true);
+
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+        Bundle bundle = new Bundle();
+        bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+        Adjustment adjustment = new Adjustment(
+                PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+        record.addAdjustment(adjustment);
+        record.applyAdjustments();
+        record.calculateImportance();
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+    }
+
+    @Test
+    public void testApplyImportanceAdjustmentsForNonOemLockedChannels() {
+        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+        channel.setImportanceLockedByOEM(false);
+
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+        Bundle bundle = new Bundle();
+        bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+        Adjustment adjustment = new Adjustment(
+                PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+        record.addAdjustment(adjustment);
+        record.applyAdjustments();
+        record.calculateImportance();
+
+        assertEquals(IMPORTANCE_LOW, record.getImportance());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 0b73481..0fcfea7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2187,4 +2187,121 @@
         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
     }
+
+    @Test
+    public void testLockChannelsForOEM_emptyList() {
+        mHelper.lockChannelsForOEM(null);
+        mHelper.lockChannelsForOEM(new String[0]);
+        // no exception
+    }
+
+    @Test
+    public void testLockChannelsForOEM_appWide() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+        // different uids, same package
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+        mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
+        mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_onlyGivenPkg() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, 30, b, false, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+        assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 30, b.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_channelSpecific() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+        // different uids, same package
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+        mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
+        mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"});
+
+        assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_channelDoesNotExistYet_appWide() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+
+        mHelper.createNotificationChannel(PKG_O, 3, b, true, false);
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_channelDoesNotExistYet_channelSpecific() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O + ":a", PKG_O + ":b"});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByOEM());
+
+        mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testUpdateNotificationChannel_oemLockedImportance() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
+        update.setAllowAppOverlay(false);
+
+        mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+        assertEquals(IMPORTANCE_HIGH,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+        assertEquals(false,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canOverlayApps());
+
+        mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+        assertEquals(IMPORTANCE_HIGH,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b6f1817..8f9d2ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -20,6 +20,9 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
@@ -38,6 +41,7 @@
 import android.app.ActivityOptions;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.MutableBoolean;
@@ -210,4 +214,41 @@
         assertNull(mActivity.pendingOptions);
         assertNotNull(activity2.pendingOptions);
     }
+
+    @Test
+    public void testNewOverrideConfigurationIncrementsSeq() {
+        final Configuration newConfig = new Configuration();
+
+        final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+        mActivity.onRequestedOverrideConfigurationChanged(newConfig);
+        assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
+    }
+
+    @Test
+    public void testNewParentConfigurationIncrementsSeq() {
+        final Configuration newConfig = new Configuration(
+                mTask.getRequestedOverrideConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+
+        final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+        assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
+    }
+
+    @Test
+    public void testNotifiesSeqIncrementToAppToken() {
+        final Configuration appWindowTokenRequestedOrientation = mock(Configuration.class);
+        mActivity.mAppWindowToken = mock(AppWindowToken.class);
+        doReturn(appWindowTokenRequestedOrientation).when(mActivity.mAppWindowToken)
+                .getRequestedOverrideConfiguration();
+
+        final Configuration newConfig = new Configuration();
+        newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
+
+        final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+        mActivity.onRequestedOverrideConfigurationChanged(newConfig);
+        assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
+        verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index bd29d2a..5589ca1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -66,7 +66,7 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.app.IVoiceInteractor;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.ServiceThread;
 import com.android.server.am.ActivityManagerService;
@@ -264,6 +264,8 @@
                     .setOrientation(anyInt(), any(), any());
             doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt());
             doNothing().when(activity).removeWindowContainer();
+            doReturn(mock(Configuration.class)).when(activity.mAppWindowToken)
+                    .getRequestedOverrideConfiguration();
 
             if (mTaskRecord != null) {
                 mTaskRecord.addActivityToTop(activity);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index f1c6eab..bb3ab35 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -20,11 +20,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -125,7 +123,6 @@
         mDisplayContent = spy(mDisplayContent);
         mWindow = createDropTargetWindow("Drag test window", 0);
         doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
-        when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
 
         synchronized (mWm.mGlobalLock) {
             mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
@@ -176,7 +173,6 @@
                     .setFormat(PixelFormat.TRANSLUCENT)
                     .build();
 
-            assertTrue(mWm.mInputManager.transferTouchFocus(null, null));
             mToken = mTarget.performDrag(
                     new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
                     data);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index c343fe7..8c6ac23 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -18,7 +18,6 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -58,10 +57,6 @@
         assertNotNull(mWm.mTaskPositioningController);
         mTarget = mWm.mTaskPositioningController;
 
-        when(mWm.mInputManager.transferTouchFocus(
-                any(InputChannel.class),
-                any(InputChannel.class))).thenReturn(true);
-
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
         mWindow.mInputChannel = new InputChannel();
         synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
new file mode 100644
index 0000000..8d83497
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoOutputStream;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+
+/**
+ * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:WindowTraceBufferTest
+ */
+@SmallTest
+@Presubmit
+public class WindowTraceBufferTest {
+    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+    private File mFile;
+
+    @Before
+    public void setUp() throws Exception {
+        final Context testContext = getInstrumentation().getContext();
+        mFile = testContext.getFileStreamPath("tracing_test.dat");
+        mFile.delete();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mFile.delete();
+    }
+
+    @Test
+    public void testTraceQueueBuffer_addItem() throws Exception {
+        ProtoOutputStream toWrite1 = getDummy(1);
+        ProtoOutputStream toWrite2 = getDummy(2);
+        ProtoOutputStream toWrite3 = getDummy(3);
+        byte[] toWrite1Bytes = toWrite1.getBytes();
+        byte[] toWrite2Bytes = toWrite2.getBytes();
+        byte[] toWrite3Bytes = toWrite3.getBytes();
+
+        final int objectSize = toWrite1.getBytes().length;
+        final int bufferCapacity = objectSize * 2;
+
+        final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity);
+
+        buffer.add(toWrite1);
+        assertTrue("First element should be in the list",
+                buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes)));
+
+        buffer.add(toWrite2);
+        assertTrue("First element should be in the list",
+                buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes)));
+        assertTrue("Second element should be in the list",
+                buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite2Bytes)));
+
+        buffer.add(toWrite3);
+
+        assertTrue("Third element should not be in the list",
+                buffer.mBuffer.stream().noneMatch(p -> Arrays.equals(p, toWrite3Bytes)));
+
+        assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
+        assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
+                buffer.mBufferSize, bufferCapacity);
+        assertEquals("Buffer is full, available space should be 0",
+                buffer.getAvailableSpace(), 0);
+    }
+
+    private ProtoOutputStream getDummy(int value) {
+        ProtoOutputStream toWrite = new ProtoOutputStream();
+        toWrite.write(MAGIC_NUMBER, value);
+        toWrite.flush();
+
+        return toWrite;
+    }
+
+    private WindowTraceBuffer buildQueueBuffer(int size) throws IOException {
+        return new WindowTraceQueueBuffer(size, mFile, false);
+    }
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2820836..dcaa499 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -239,6 +239,30 @@
             "android.telecom.event.HANDOVER_FAILED";
 
     public static class Details {
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+                prefix = { "DIRECTION_" },
+                value = {DIRECTION_UNKNOWN, DIRECTION_INCOMING, DIRECTION_OUTGOING})
+        public @interface CallDirection {}
+
+        /**
+         * Indicates that the call is neither and incoming nor an outgoing call.  This can be the
+         * case for calls reported directly by a {@link ConnectionService} in special cases such as
+         * call handovers.
+         */
+        public static final int DIRECTION_UNKNOWN = -1;
+
+        /**
+         * Indicates that the call is an incoming call.
+         */
+        public static final int DIRECTION_INCOMING = 0;
+
+        /**
+         * Indicates that the call is an outgoing call.
+         */
+        public static final int DIRECTION_OUTGOING = 1;
+
 
         /** Call can currently be put on hold or unheld. */
         public static final int CAPABILITY_HOLD = 0x00000001;
@@ -519,6 +543,7 @@
         private final Bundle mIntentExtras;
         private final long mCreationTimeMillis;
         private final CallIdentification mCallIdentification;
+        private final @CallDirection int mCallDirection;
 
         /**
          * Whether the supplied capabilities  supports the specified capability.
@@ -838,6 +863,14 @@
             return mCallIdentification;
         }
 
+        /**
+         * Indicates whether the call is an incoming or outgoing call.
+         * @return The call's direction.
+         */
+        public @CallDirection int getCallDirection() {
+            return mCallDirection;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (o instanceof Details) {
@@ -859,7 +892,8 @@
                         areBundlesEqual(mExtras, d.mExtras) &&
                         areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
                         Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
-                        Objects.equals(mCallIdentification, d.mCallIdentification);
+                        Objects.equals(mCallIdentification, d.mCallIdentification) &&
+                        Objects.equals(mCallDirection, d.mCallDirection);
             }
             return false;
         }
@@ -881,7 +915,8 @@
                             mExtras,
                             mIntentExtras,
                             mCreationTimeMillis,
-                            mCallIdentification);
+                            mCallIdentification,
+                            mCallDirection);
         }
 
         /** {@hide} */
@@ -902,7 +937,8 @@
                 Bundle extras,
                 Bundle intentExtras,
                 long creationTimeMillis,
-                CallIdentification callIdentification) {
+                CallIdentification callIdentification,
+                int callDirection) {
             mTelecomCallId = telecomCallId;
             mHandle = handle;
             mHandlePresentation = handlePresentation;
@@ -920,6 +956,7 @@
             mIntentExtras = intentExtras;
             mCreationTimeMillis = creationTimeMillis;
             mCallIdentification = callIdentification;
+            mCallDirection = callDirection;
         }
 
         /** {@hide} */
@@ -941,7 +978,8 @@
                     parcelableCall.getExtras(),
                     parcelableCall.getIntentExtras(),
                     parcelableCall.getCreationTimeMillis(),
-                    parcelableCall.getCallIdentification());
+                    parcelableCall.getCallIdentification(),
+                    parcelableCall.getCallDirection());
         }
 
         @Override
diff --git a/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java
index 97af06c..87834fd 100644
--- a/telecomm/java/android/telecom/CallIdentification.java
+++ b/telecomm/java/android/telecom/CallIdentification.java
@@ -250,8 +250,8 @@
         mDetails = details;
         mPhoto = photo;
         mNuisanceConfidence = nuisanceConfidence;
-        mCallScreeningAppName = callScreeningPackageName;
-        mCallScreeningPackageName = callScreeningAppName;
+        mCallScreeningAppName = callScreeningAppName;
+        mCallScreeningPackageName = callScreeningPackageName;
     }
 
     private String mName;
@@ -430,4 +430,22 @@
         return Objects.hash(mName, mDescription, mDetails, mPhoto, mNuisanceConfidence,
                 mCallScreeningAppName, mCallScreeningPackageName);
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[CallId mName=");
+        sb.append(Log.pii(mName));
+        sb.append(", mDesc=");
+        sb.append(mDescription);
+        sb.append(", mDet=");
+        sb.append(mDetails);
+        sb.append(", conf=");
+        sb.append(mNuisanceConfidence);
+        sb.append(", appName=");
+        sb.append(mCallScreeningAppName);
+        sb.append(", pkgName=");
+        sb.append(mCallScreeningPackageName);
+        return sb.toString();
+    }
 }
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index be96b3c..826ad82 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -21,6 +21,7 @@
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -33,8 +34,9 @@
 
 /**
  * This service can be implemented by the default dialer (see
- * {@link TelecomManager#getDefaultDialerPackage()}) to allow or disallow incoming calls before
- * they are shown to a user.
+ * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
+ * incoming calls before they are shown to a user.  This service can also provide
+ * {@link CallIdentification} information for calls.
  * <p>
  * Below is an example manifest registration for a {@code CallScreeningService}.
  * <pre>
@@ -56,6 +58,34 @@
  *     information about a {@link Call.Details call} which will be shown to the user in the
  *     Dialer app.</li>
  * </ol>
+ * <p>
+ * <h2>Becoming the {@link CallScreeningService}</h2>
+ * Telecom will bind to a single app chosen by the user which implements the
+ * {@link CallScreeningService} API when there are new incoming and outgoing calls.
+ * <p>
+ * The code snippet below illustrates how your app can request that it fills the call screening
+ * role.
+ * <pre>
+ * {@code
+ * private static final int REQUEST_ID = 1;
+ *
+ * public void requestRole() {
+ *     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
+ *     Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP");
+ *     startActivityForResult(intent, REQUEST_ID);
+ * }
+ *
+ * &#64;Override
+ * public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ *     if (requestCode == REQUEST_ID) {
+ *         if (resultCode == android.app.Activity.RESULT_OK) {
+ *             // Your app is now the call screening app
+ *         } else {
+ *             // Your app is not the call screening app
+ *         }
+ *     }
+ * }
+ * </pre>
  */
 public abstract class CallScreeningService extends Service {
     /**
@@ -222,30 +252,46 @@
     }
 
     /**
-     * Called when a new incoming call is added.
-     * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
-     * should be called to allow or disallow the call.
+     * Called when a new incoming or outgoing call is added which is not in the user's contact list.
+     * <p>
+     * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
+     * calling
+     * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}.
+     * Your app can tell if a call is an incoming call by checking to see if
+     * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
+     * <p>
+     * For incoming or outgoing calls, the {@link CallScreeningService} can call
+     * {@link #provideCallIdentification(Call.Details, CallIdentification)} in order to provide
+     * {@link CallIdentification} for the call.
      * <p>
      * Note: The {@link Call.Details} instance provided to a call screening service will only have
      * the following properties set.  The rest of the {@link Call.Details} properties will be set to
      * their default value or {@code null}.
      * <ul>
-     *     <li>{@link Call.Details#getState()}</li>
+     *     <li>{@link Call.Details#getCallDirection()}</li>
      *     <li>{@link Call.Details#getConnectTimeMillis()}</li>
      *     <li>{@link Call.Details#getCreationTimeMillis()}</li>
      *     <li>{@link Call.Details#getHandle()}</li>
      *     <li>{@link Call.Details#getHandlePresentation()}</li>
      * </ul>
+     * <p>
+     * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
+     * is {@link PhoneAccount#SCHEME_TEL} are passed for call
+     * screening.  Further, only calls which are not in the user's contacts are passed for
+     * screening.  For outgoing calls, no post-dial digits are passed.
      *
-     * @param callDetails Information about a new incoming call, see {@link Call.Details}.
+     * @param callDetails Information about a new call, see {@link Call.Details}.
      */
     public abstract void onScreenCall(@NonNull Call.Details callDetails);
 
     /**
-     * Responds to the given call, either allowing it or disallowing it.
+     * Responds to the given incoming call, either allowing it or disallowing it.
      * <p>
      * The {@link CallScreeningService} calls this method to inform the system whether the call
      * should be silently blocked or not.
+     * <p>
+     * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
+     * {@link Call.Details#DIRECTION_INCOMING}.
      *
      * @param callDetails The call to allow.
      *                    <p>
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 1aeeca7..f5f0af7 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -40,11 +40,30 @@
 import java.util.List;
 
 /**
- * This service is implemented by any app that wishes to provide the user-interface for managing
- * phone calls. Telecom binds to this service while there exists a live (active or incoming) call,
- * and uses it to notify the in-call app of any live and recently disconnected calls. An app must
- * first be set as the default phone app (See {@link TelecomManager#getDefaultDialerPackage()})
- * before the telecom service will bind to its {@code InCallService} implementation.
+ * This service is implemented by an app that wishes to provide functionality for managing
+ * phone calls.
+ * <p>
+ * There are three types of apps which Telecom can bind to when there exists a live (active or
+ * incoming) call:
+ * <ol>
+ *     <li>Default Dialer/Phone app - the default dialer/phone app is one which provides the
+ *     in-call user interface while the device is in a call.  A device is bundled with a system
+ *     provided default dialer/phone app.  The user may choose a single app to take over this role
+ *     from the system app.</li>
+ *     <li>Default Car-mode Dialer/Phone app - the default car-mode dialer/phone app is one which
+ *     provides the in-call user interface while the device is in a call and the device is in car
+ *     mode.  The user may choose a single app to fill this role.</li>
+ *     <li>Call Companion app - a call companion app is one which provides no user interface itself,
+ *     but exposes call information to another display surface, such as a wearable device.  The
+ *     user may choose multiple apps to fill this role.</li>
+ * </ol>
+ * <p>
+ * Apps which wish to fulfill one of the above roles use the {@link android.app.role.RoleManager}
+ * to request that they fill the desired role.
+ *
+ * <h2>Becoming the Default Phone App</h2>
+ * An app filling the role of the default phone app provides a user interface while the device is in
+ * a call, and the device is not in car mode.
  * <p>
  * Below is an example manifest registration for an {@code InCallService}. The meta-data
  * {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular
@@ -82,12 +101,34 @@
  * }
  * </pre>
  * <p>
- * When a user installs your application and runs it for the first time, you should prompt the user
- * to see if they would like your application to be the new default phone app.  See the
- * {@link TelecomManager#ACTION_CHANGE_DEFAULT_DIALER} intent documentation for more information on
- * how to do this.
+ * When a user installs your application and runs it for the first time, you should use the
+ * {@link android.app.role.RoleManager} to prompt the user to see if they would like your app to
+ * be the new default phone app.
+ * <p id="requestRole">
+ * The code below shows how your app can request to become the default phone/dialer app:
+ * <pre>
+ * {@code
+ * private static final int REQUEST_ID = 1;
+ *
+ * public void requestRole() {
+ *     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
+ *     Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
+ *     startActivityForResult(intent, REQUEST_ID);
+ * }
+ *
+ * &#64;Override
+ * public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ *     if (requestCode == REQUEST_ID) {
+ *         if (resultCode == android.app.Activity.RESULT_OK) {
+ *             // Your app is now the default dialer app
+ *         } else {
+ *             // Your app is not the default dialer app
+ *         }
+ *     }
+ * }
+ * </pre>
  * <p id="incomingCallNotification">
- * <h2>Showing the Incoming Call Notification</h2>
+ * <h3>Showing the Incoming Call Notification</h3>
  * When your app receives a new incoming call via {@link InCallService#onCallAdded(Call)}, it is
  * responsible for displaying an incoming call UI for the incoming call.  It should do this using
  * {@link android.app.NotificationManager} APIs to post a new incoming call notification.
@@ -121,7 +162,7 @@
  * heads-up notification if the user is actively using the phone.  When the user is not using the
  * phone, your full-screen incoming call UI is used instead.
  * For example:
- * <pre><code>
+ * <pre><code>{@code
  * // Create an intent which triggers your fullscreen incoming call user interface.
  * Intent intent = new Intent(Intent.ACTION_MAIN, null);
  * intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -151,7 +192,49 @@
  * NotificationManager notificationManager = mContext.getSystemService(
  *     NotificationManager.class);
  * notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
- * </code></pre>
+ * }</pre>
+ * <p>
+ * <h2>Becoming the Default Car-mode Phone App</h2>
+ * An app filling the role of the default car-mode dialer/phone app provides a user interface while
+ * the device is in a call, and in car mode.  See
+ * {@link android.app.UiModeManager#ACTION_ENTER_CAR_MODE} for more information about car mode.
+ * When the device is in car mode, Telecom binds to the default car-mode dialer/phone app instead
+ * of the usual dialer/phone app.
+ * <p>
+ * Similar to the requirements for becoming the default dialer/phone app, your app must declare a
+ * manifest entry for its {@link InCallService} implementation.  Your manifest entry should ensure
+ * the following conditions are met:
+ * <ul>
+ *     <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li>
+ *     <li>Set the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} metadata to
+ *     {@code true}<li>
+ *     <li>Your app must request the permission
+ *     {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
+ * </ul>
+ * <p>
+ * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER_APP} in order to
+ * become the default (see <a href="#requestRole">above</a> for how to request your app fills this
+ * role).
+ *
+ * <h2>Becoming a Call Companion App</h2>
+ * An app which fills the companion app role does not directly provide a user interface while the
+ * device is in a call.  Instead, it is typically used to relay information about calls to another
+ * display surface, such as a wearable device.
+ * <p>
+ * Similar to the requirements for becoming the default dialer/phone app, your app must declare a
+ * manifest entry for its {@link InCallService} implementation.  Your manifest entry should
+ * ensure the following conditions are met:
+ * <ul>
+ *     <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li>
+ *     <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI}
+ *     metadata.</li>
+ *     <li>Your app must request the permission
+ *     {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
+ * </ul>
+ * <p>
+ * Your app should request to fill the role {@code android.app.role.CALL_COMPANION_APP} in order to
+ * become a call companion app (see <a href="#requestRole">above</a> for how to request your app
+ * fills this role).
  */
 public abstract class InCallService extends Service {
 
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 911786e..f7dec83 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.telecom.Call.Details.CallDirection;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -64,6 +65,7 @@
     private final Bundle mExtras;
     private final long mCreationTimeMillis;
     private final CallIdentification mCallIdentification;
+    private final int mCallDirection;
 
     public ParcelableCall(
             String id,
@@ -92,7 +94,8 @@
             Bundle intentExtras,
             Bundle extras,
             long creationTimeMillis,
-            CallIdentification callIdentification) {
+            CallIdentification callIdentification,
+            int callDirection) {
         mId = id;
         mState = state;
         mDisconnectCause = disconnectCause;
@@ -120,6 +123,7 @@
         mExtras = extras;
         mCreationTimeMillis = creationTimeMillis;
         mCallIdentification = callIdentification;
+        mCallDirection = callDirection;
     }
 
     /** The unique ID of the call. */
@@ -318,6 +322,13 @@
         return mCallIdentification;
     }
 
+    /**
+     * Indicates whether the call is an incoming or outgoing call.
+     */
+    public @CallDirection int getCallDirection() {
+        return mCallDirection;
+    }
+
     /** Responsible for creating ParcelableCall objects for deserialized Parcels. */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final Parcelable.Creator<ParcelableCall> CREATOR =
@@ -356,6 +367,7 @@
             ParcelableRttCall rttCall = source.readParcelable(classLoader);
             long creationTimeMillis = source.readLong();
             CallIdentification callIdentification = source.readParcelable(classLoader);
+            int callDirection = source.readInt();
             return new ParcelableCall(
                     id,
                     state,
@@ -383,7 +395,8 @@
                     intentExtras,
                     extras,
                     creationTimeMillis,
-                    callIdentification);
+                    callIdentification,
+                    callDirection);
         }
 
         @Override
@@ -429,6 +442,7 @@
         destination.writeParcelable(mRttCall, 0);
         destination.writeLong(mCreationTimeMillis);
         destination.writeParcelable(mCallIdentification, 0);
+        destination.writeInt(mCallDirection);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationStates.java b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
index 5d809d0..d6a8065 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationStates.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
@@ -44,13 +44,19 @@
      */
     public final boolean isEnDcAvailable;
 
+    /**
+     * Provides network support info for LTE VoPS and LTE Emergency bearer support
+     */
+    public final LteVopsSupportInfo lteVopsSupportInfo;
+
     DataSpecificRegistrationStates(
             int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
-            boolean isEnDcAvailable) {
+            boolean isEnDcAvailable, LteVopsSupportInfo lteVops) {
         this.maxDataCalls = maxDataCalls;
         this.isDcNrRestricted = isDcNrRestricted;
         this.isNrAvailable = isNrAvailable;
         this.isEnDcAvailable = isEnDcAvailable;
+        this.lteVopsSupportInfo = lteVops;
     }
 
     private DataSpecificRegistrationStates(Parcel source) {
@@ -58,6 +64,7 @@
         isDcNrRestricted = source.readBoolean();
         isNrAvailable = source.readBoolean();
         isEnDcAvailable = source.readBoolean();
+        lteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
     }
 
     @Override
@@ -66,6 +73,7 @@
         dest.writeBoolean(isDcNrRestricted);
         dest.writeBoolean(isNrAvailable);
         dest.writeBoolean(isEnDcAvailable);
+        lteVopsSupportInfo.writeToParcel(dest, flags);
     }
 
     @Override
@@ -81,13 +89,15 @@
                 .append(" isDcNrRestricted = " + isDcNrRestricted)
                 .append(" isNrAvailable = " + isNrAvailable)
                 .append(" isEnDcAvailable = " + isEnDcAvailable)
+                .append(lteVopsSupportInfo.toString())
                 .append(" }")
                 .toString();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable);
+        return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
+            lteVopsSupportInfo);
     }
 
     @Override
@@ -100,7 +110,8 @@
         return this.maxDataCalls == other.maxDataCalls
                 && this.isDcNrRestricted == other.isDcNrRestricted
                 && this.isNrAvailable == other.isNrAvailable
-                && this.isEnDcAvailable == other.isEnDcAvailable;
+                && this.isEnDcAvailable == other.isEnDcAvailable
+                && this.lteVopsSupportInfo.equals(other.lteVopsSupportInfo);
     }
 
     public static final Parcelable.Creator<DataSpecificRegistrationStates> CREATOR =
@@ -115,4 +126,4 @@
                     return new DataSpecificRegistrationStates[size];
                 }
             };
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.aidl b/telephony/java/android/telephony/LteVopsSupportInfo.aidl
new file mode 100644
index 0000000..5984598
--- /dev/null
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable LteVopsSupportInfo;
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.java b/telephony/java/android/telephony/LteVopsSupportInfo.java
new file mode 100644
index 0000000..0ae85c0
--- /dev/null
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.java
@@ -0,0 +1,137 @@
+/*
+ * 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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class stores information related to LTE network VoPS support
+ * @hide
+ */
+@SystemApi
+public final class LteVopsSupportInfo implements Parcelable {
+
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            value = {LTE_STATUS_NOT_AVAILABLE, LTE_STATUS_SUPPORTED,
+                    LTE_STATUS_NOT_SUPPORTED}, prefix = "LTE_STATUS_")
+    public @interface LteVopsStatus {}
+    /**
+     * Indicates information not available from modem.
+     */
+    public static final int LTE_STATUS_NOT_AVAILABLE = 1;
+
+    /**
+     * Indicates network support the feature.
+     */
+    public static final int LTE_STATUS_SUPPORTED = 2;
+
+    /**
+     * Indicates network does not support the feature.
+     */
+    public static final int LTE_STATUS_NOT_SUPPORTED = 3;
+
+    @LteVopsStatus
+    private final int mVopsSupport;
+    @LteVopsStatus
+    private final int mEmcBearerSupport;
+
+    public LteVopsSupportInfo(@LteVopsStatus int vops, @LteVopsStatus int emergency) {
+        mVopsSupport = vops;
+        mEmcBearerSupport = emergency;
+    }
+
+    /**
+     * Provides the LTE VoPS support capability as described in:
+     * 3GPP 24.301 EPS network feature support -> IMS VoPS
+     */
+    public @LteVopsStatus int getVopsSupport() {
+        return mVopsSupport;
+    }
+
+    /**
+     * Provides the LTE Emergency bearer support capability as described in:
+     *    3GPP 24.301 EPS network feature support -> EMC BS
+     *    25.331 LTE RRC SIB1 : ims-EmergencySupport-r9
+     */
+    public @LteVopsStatus int getEmcBearerSupport() {
+        return mEmcBearerSupport;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mVopsSupport);
+        out.writeInt(mEmcBearerSupport);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof LteVopsSupportInfo)) {
+            return false;
+        }
+        if (this == o) return true;
+        LteVopsSupportInfo other = (LteVopsSupportInfo) o;
+        return mVopsSupport == other.mVopsSupport
+            && mEmcBearerSupport == other.mEmcBearerSupport;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mVopsSupport, mEmcBearerSupport);
+    }
+
+    /**
+     * @return string representation.
+     */
+    @Override
+    public String toString() {
+        return ("LteVopsSupportInfo : "
+                + " mVopsSupport = " + mVopsSupport
+                + " mEmcBearerSupport = " + mEmcBearerSupport);
+    }
+
+    public static final Creator<LteVopsSupportInfo> CREATOR =
+            new Creator<LteVopsSupportInfo>() {
+        @Override
+        public LteVopsSupportInfo createFromParcel(Parcel in) {
+            return new LteVopsSupportInfo(in);
+        }
+
+        @Override
+        public LteVopsSupportInfo[] newArray(int size) {
+            return new LteVopsSupportInfo[size];
+        }
+    };
+
+    private LteVopsSupportInfo(Parcel in) {
+        mVopsSupport = in.readInt();
+        mEmcBearerSupport = in.readInt();
+    }
+}
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index b00665e..ceb76b5 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -219,12 +219,13 @@
     public NetworkRegistrationState(int domain, int transportType, int regState,
             int accessNetworkTechnology, int rejectCause, boolean emergencyOnly,
             int[] availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls,
-            boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable) {
+            boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable,
+            LteVopsSupportInfo lteVopsSupportInfo) {
         this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
                 availableServices, cellIdentity);
 
         mDataSpecificStates = new DataSpecificRegistrationStates(
-                maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable);
+                maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
         updateNrStatus(mDataSpecificStates);
     }
 
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 9fc1b6f..bf9bf9a 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -170,7 +170,8 @@
                     RIL_RADIO_TECHNOLOGY_GSM,
                     RIL_RADIO_TECHNOLOGY_TD_SCDMA,
                     RIL_RADIO_TECHNOLOGY_IWLAN,
-                    RIL_RADIO_TECHNOLOGY_LTE_CA})
+                    RIL_RADIO_TECHNOLOGY_LTE_CA,
+                    RIL_RADIO_TECHNOLOGY_NR})
     public @interface RilRadioTechnology {}
     /**
      * Available radio technologies for GSM, UMTS and CDMA.
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index a1e8b19..51d5ab1 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -174,6 +174,16 @@
     private boolean mIsGroupDisabled = false;
 
     /**
+     * Profile class, PROFILE_CLASS_TESTING, PROFILE_CLASS_OPERATIONAL
+     * PROFILE_CLASS_PROVISIONING, or PROFILE_CLASS_UNSET.
+     * A profile on the eUICC can be defined as test, operational, provisioning, or unset.
+     * The profile class will be populated from the profile metadata if present. Otherwise,
+     * the profile class defaults to unset if there is no profile metadata or the subscription
+     * is not on an eUICC ({@link #isEmbedded} returns false).
+     */
+    private int mProfileClass;
+
+    /**
      * @hide
      */
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
@@ -182,7 +192,8 @@
             @Nullable UiccAccessRule[] accessRules, String cardString) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
-                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID);
+                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID,
+                SubscriptionManager.PROFILE_CLASS_DEFAULT);
     }
 
     /**
@@ -192,10 +203,10 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
-            @Nullable String groupUUID, boolean isMetered, int carrierId) {
+            @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
-                isOpportunistic, groupUUID, isMetered, false, carrierId);
+                isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass);
     }
 
     /**
@@ -206,7 +217,7 @@
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
             boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
-            boolean isGroupDisabled, int carrierid) {
+            boolean isGroupDisabled, int carrierid, int profileClass) {
         this.mId = id;
         this.mIccId = iccId;
         this.mSimSlotIndex = simSlotIndex;
@@ -229,6 +240,7 @@
         this.mIsMetered = isMetered;
         this.mIsGroupDisabled = isGroupDisabled;
         this.mCarrierId = carrierid;
+        this.mProfileClass = profileClass;
     }
 
 
@@ -466,6 +478,15 @@
     }
 
     /**
+     * @return the profile class of this subscription.
+     * @hide
+     */
+    @SystemApi
+    public @SubscriptionManager.ProfileClass int getProfileClass() {
+        return this.mProfileClass;
+    }
+
+    /**
      * Checks whether the app with the given context is authorized to manage this subscription
      * according to its metadata. Only supported for embedded subscriptions (if {@link #isEmbedded}
      * returns true).
@@ -590,11 +611,12 @@
             boolean isMetered = source.readBoolean();
             boolean isGroupDisabled = source.readBoolean();
             int carrierid = source.readInt();
+            int profileClass = source.readInt();
 
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                     nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
                     isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
-                    isMetered, isGroupDisabled, carrierid);
+                    isMetered, isGroupDisabled, carrierid, profileClass);
         }
 
         @Override
@@ -627,6 +649,7 @@
         dest.writeBoolean(mIsMetered);
         dest.writeBoolean(mIsGroupDisabled);
         dest.writeInt(mCarrierId);
+        dest.writeInt(mProfileClass);
     }
 
     @Override
@@ -662,7 +685,8 @@
                 + " accessRules " + Arrays.toString(mAccessRules)
                 + " cardString=" + cardStringToPrint + " cardId=" + mCardId
                 + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
-                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled + "}";
+                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
+                + " profileClass=" + mProfileClass + "}";
     }
 
     @Override
@@ -670,7 +694,7 @@
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
                 mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
                 mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
-                mIsGroupDisabled, mCarrierId);
+                mIsGroupDisabled, mCarrierId, mProfileClass);
     }
 
     @Override
@@ -705,6 +729,7 @@
                 && Objects.equals(mCardId, toCompare.mCardId)
                 && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
                 && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
-                && Arrays.equals(mAccessRules, toCompare.mAccessRules);
+                && Arrays.equals(mAccessRules, toCompare.mAccessRules)
+                && mProfileClass == toCompare.mProfileClass;
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2c712a1..34f7abd 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -22,6 +22,7 @@
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.DurationMillisLong;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -62,6 +63,8 @@
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -599,6 +602,73 @@
      * @hide
      */
     public static final String IS_METERED = "is_metered";
+
+    /**
+     * TelephonyProvider column name for the profile class of a subscription
+     * Only present if {@link #IS_EMBEDDED} is 1.
+     * <P>Type: INTEGER (int)</P>
+     * @hide
+     */
+    public static final String PROFILE_CLASS = "profile_class";
+
+    /**
+     * Profile class of the subscription
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "PROFILE_CLASS_" }, value = {
+            PROFILE_CLASS_TESTING,
+            PROFILE_CLASS_PROVISIONING,
+            PROFILE_CLASS_OPERATIONAL,
+            PROFILE_CLASS_UNSET,
+            PROFILE_CLASS_DEFAULT
+    })
+    public @interface ProfileClass {}
+
+    /**
+     * A testing profile can be pre-loaded or downloaded onto
+     * the eUICC and provides connectivity to test equipment
+     * for the purpose of testing the device and the eUICC. It
+     * is not intended to store any operator credentials.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_TESTING = 0;
+
+    /**
+     * A provisioning profile is pre-loaded onto the eUICC and
+     * provides connectivity to a mobile network solely for the
+     * purpose of provisioning profiles.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_PROVISIONING = 1;
+
+    /**
+     * An operational profile can be pre-loaded or downloaded
+     * onto the eUICC and provides services provided by the
+     * operator.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_OPERATIONAL = 2;
+
+    /**
+     * The profile class is unset. This occurs when profile class
+     * info is not available. The subscription either has no profile
+     * metadata or the profile metadata did not encode profile class.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_UNSET = -1;
+
+    /**
+     * Default profile class
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+
     /**
      * Broadcast Action: The user has changed one of the default subs related to
      * data, phone calls, or sms</p>
@@ -1102,17 +1172,33 @@
     @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;
+        return getActiveSubscriptionInfoList(false);
+    }
+
+    /**
+     * This is similar to {@link #getActiveSubscriptionInfoList()}, but if userVisibleOnly
+     * is true, it will filter out the hidden subscriptions.
+     *
+     * @hide
+     */
+    public List<SubscriptionInfo> getActiveSubscriptionInfoList(boolean userVisibleOnly) {
+        List<SubscriptionInfo> activeList = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
+                activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
             }
         } catch (RemoteException ex) {
             // ignore it
         }
-        return result;
+
+        if (!userVisibleOnly || activeList == null) {
+            return activeList;
+        } else {
+            return activeList.stream().filter(subInfo -> !shouldHideSubscription(subInfo))
+                    .collect(Collectors.toList());
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6484005..b48a1ce 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -76,8 +76,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.ITelecomService;
 import com.android.internal.telephony.CellNetworkScanResult;
-import com.android.internal.telephony.IAns;
 import com.android.internal.telephony.INumberVerificationCallback;
+import com.android.internal.telephony.IOns;
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.ITelephonyRegistry;
@@ -4651,8 +4651,8 @@
         return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
     }
 
-    private IAns getIAns() {
-        return IAns.Stub.asInterface(ServiceManager.getService("ians"));
+    private IOns getIOns() {
+        return IOns.Stub.asInterface(ServiceManager.getService("ions"));
     }
 
     //
@@ -9456,10 +9456,10 @@
     }
 
     /**
-     * Enable or disable AlternativeNetworkService.
+     * Enable or disable OpportunisticNetworkService.
      *
      * This method should be called to enable or disable
-     * AlternativeNetwork service on the device.
+     * OpportunisticNetwork service on the device.
      *
      * <p>
      * Requires Permission:
@@ -9470,25 +9470,25 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean setAlternativeNetworkState(boolean enable) {
+    public boolean setOpportunisticNetworkState(boolean enable) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean ret = false;
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                ret = iAlternativeNetworkService.setEnable(enable, pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                ret = iOpportunisticNetworkService.setEnable(enable, pkgForDebug);
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+            Rlog.e(TAG, "enableOpportunisticNetwork RemoteException", ex);
         }
 
         return ret;
     }
 
     /**
-     * is AlternativeNetworkService enabled
+     * is OpportunisticNetworkService enabled
      *
-     * This method should be called to determine if the AlternativeNetworkService is
+     * This method should be called to determine if the OpportunisticNetworkService is
      * enabled
      *
      * <p>
@@ -9497,17 +9497,17 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public boolean isAlternativeNetworkEnabled() {
+    public boolean isOpportunisticNetworkEnabled() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean isEnabled = false;
 
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                isEnabled = iAlternativeNetworkService.isEnabled(pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                isEnabled = iOpportunisticNetworkService.isEnabled(pkgForDebug);
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+            Rlog.e(TAG, "enableOpportunisticNetwork RemoteException", ex);
         }
 
         return isEnabled;
@@ -9862,9 +9862,9 @@
     public boolean setPreferredOpportunisticDataSubscription(int subId) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                return iAlternativeNetworkService.setPreferredData(subId, pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                return iOpportunisticNetworkService.setPreferredData(subId, pkgForDebug);
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setPreferredData RemoteException", ex);
@@ -9886,9 +9886,9 @@
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                subId = iAlternativeNetworkService.getPreferredData(pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                subId = iOpportunisticNetworkService.getPreferredData(pkgForDebug);
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getPreferredData RemoteException", ex);
@@ -9899,8 +9899,8 @@
     /**
      * Update availability of a list of networks in the current location.
      *
-     * This api should be called to inform AlternativeNetwork Service about the availability
-     * of a network at the current location. This information will be used by AlternativeNetwork
+     * This api should be called to inform OpportunisticNetwork Service about the availability
+     * of a network at the current location. This information will be used by OpportunisticNetwork
      * service to decide to attach to the network opportunistically. If an empty list is passed,
      * it is assumed that no network is available.
      * Requires that the calling app has carrier privileges on both primary and
@@ -9915,9 +9915,9 @@
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean ret = false;
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                ret = iAlternativeNetworkService.updateAvailableNetworks(availableNetworks,
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                ret = iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks,
                         pkgForDebug);
             }
         } catch (RemoteException ex) {
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index a94b163..a5f56bb 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -232,18 +232,21 @@
     private final String mCountryIso;
     private final String mMnc;
     private final int mEmergencyServiceCategoryBitmask;
+    private final List<String> mEmergencyUrns;
     private final int mEmergencyNumberSourceBitmask;
     private final int mEmergencyCallRouting;
 
     /** @hide */
     public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc,
                            @EmergencyServiceCategories int emergencyServiceCategories,
+                           @NonNull List<String> emergencyUrns,
                            @EmergencyNumberSources int emergencyNumberSources,
                            @EmergencyCallRouting int emergencyCallRouting) {
         this.mNumber = number;
         this.mCountryIso = countryIso;
         this.mMnc = mnc;
         this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
+        this.mEmergencyUrns = emergencyUrns;
         this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
         this.mEmergencyCallRouting = emergencyCallRouting;
     }
@@ -254,6 +257,7 @@
         mCountryIso = source.readString();
         mMnc = source.readString();
         mEmergencyServiceCategoryBitmask = source.readInt();
+        mEmergencyUrns = source.createStringArrayList();
         mEmergencyNumberSourceBitmask = source.readInt();
         mEmergencyCallRouting = source.readInt();
     }
@@ -265,6 +269,7 @@
         dest.writeString(mCountryIso);
         dest.writeString(mMnc);
         dest.writeInt(mEmergencyServiceCategoryBitmask);
+        dest.writeStringList(mEmergencyUrns);
         dest.writeInt(mEmergencyNumberSourceBitmask);
         dest.writeInt(mEmergencyCallRouting);
     }
@@ -345,6 +350,22 @@
     }
 
     /**
+     * Returns the list of emergency Uniform Resources Names (URN) of the emergency number.
+     *
+     * For example, {@code urn:service:sos} is the generic URN for contacting emergency services
+     * of all type.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            RFC 5031
+     *
+     * @return list of emergency Uniform Resources Names (URN) or an empty list if the emergency
+     *         number does not have a specified emergency Uniform Resource Name.
+     */
+    public @NonNull List<String> getEmergencyUrns() {
+        return mEmergencyUrns;
+    }
+
+    /**
      * Checks if the emergency service category is unspecified for the emergency number
      * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}.
      *
@@ -434,6 +455,7 @@
         return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
                 + "|Mnc-" + mMnc
                 + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
+                + "|Urns-" + mEmergencyUrns
                 + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask)
                 + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting);
     }
@@ -448,6 +470,7 @@
                 && mCountryIso.equals(other.mCountryIso)
                 && mMnc.equals(other.mMnc)
                 && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask
+                && mEmergencyUrns.equals(other.mEmergencyUrns)
                 && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask
                 && mEmergencyCallRouting == other.mEmergencyCallRouting;
     }
@@ -455,7 +478,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask,
-                mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
+                mEmergencyUrns, mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
     }
 
     /**
@@ -584,6 +607,9 @@
                 != second.getEmergencyServiceCategoryBitmask()) {
             return false;
         }
+        if (first.getEmergencyUrns().equals(second.getEmergencyUrns())) {
+            return false;
+        }
         if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
             return false;
         }
@@ -605,6 +631,7 @@
         if (areSameEmergencyNumbers(first, second)) {
             return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
                     first.getEmergencyServiceCategoryBitmask(),
+                    first.getEmergencyUrns(),
                     first.getEmergencyNumberSourceBitmask()
                             | second.getEmergencyNumberSourceBitmask(),
                     first.getEmergencyCallRouting());
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 6326cc6..cc9befe 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -616,14 +616,13 @@
     /**
      * Update the nickname for the given subscription.
      *
-     * <p>Requires that the calling app has the
-     * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
-     * internal system use only.
+     * <p>Requires that the calling app has carrier privileges according to the metadata of the
+     * profile to be updated, or the
+     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
      *
      * @param subscriptionId the ID of the subscription to update.
      * @param nickname the new nickname to apply.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
-     * @hide
      */
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void updateSubscriptionNickname(
@@ -634,7 +633,7 @@
         }
         try {
             getIEuiccController().updateSubscriptionNickname(
-                    subscriptionId, nickname, callbackIntent);
+                    subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 9c8d078..525a96a 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -33,6 +33,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Parcelable object to handle IMS call profile.
@@ -323,6 +325,15 @@
             EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
 
     /**
+     * The emergency Uniform Resource Names (URN), only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    private List<String> mEmergencyUrns = new ArrayList<>();
+
+    /**
      * The emergency call routing, only valid if {@link #getServiceType} returns
      * {@link #SERVICE_TYPE_EMERGENCY}
      *
@@ -524,6 +535,7 @@
                 + ", restrictCause=" + mRestrictCause
                 + ", mediaProfile=" + mMediaProfile.toString()
                 + ", emergencyServiceCategories=" + mEmergencyCallRouting
+                + ", emergencyUrns=" + mEmergencyUrns
                 + ", emergencyCallRouting=" + mEmergencyCallRouting + " }";
     }
 
@@ -540,6 +552,7 @@
         out.writeBundle(filteredExtras);
         out.writeParcelable(mMediaProfile, 0);
         out.writeInt(mEmergencyServiceCategories);
+        out.writeStringList(mEmergencyUrns);
         out.writeInt(mEmergencyCallRouting);
     }
 
@@ -549,6 +562,7 @@
         mCallExtras = in.readBundle();
         mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader());
         mEmergencyServiceCategories = in.readInt();
+        mEmergencyUrns = in.createStringArrayList();
         mEmergencyCallRouting = in.readInt();
     }
 
@@ -760,20 +774,21 @@
     }
 
     /**
-     * Set the emergency service categories and emergency call routing. The set value is valid
+     * Set the emergency number information. The set value is valid
      * only if {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
      *
      * Reference: 3gpp 23.167, Section 6 - Functional description;
+     *            3gpp 24.503, Section 5.1.6.8.1 - General;
      *            3gpp 22.101, Section 10 - Emergency Calls.
      *
      * @hide
      */
     public void setEmergencyCallInfo(EmergencyNumber num) {
         setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask());
+        setEmergencyUrns(num.getEmergencyUrns());
         setEmergencyCallRouting(num.getEmergencyCallRouting());
     }
 
-
     /**
      * Set the emergency service categories. The set value is valid only if
      * {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
@@ -800,6 +815,18 @@
     }
 
     /**
+     * Set the emergency Uniform Resource Names (URN), only valid if {@link #getServiceType}
+     * returns {@link #SERVICE_TYPE_EMERGENCY}.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    @VisibleForTesting
+    public void setEmergencyUrns(List<String> emergencyUrns) {
+        mEmergencyUrns = emergencyUrns;
+    }
+
+    /**
      * Set the emergency call routing, only valid if {@link #getServiceType} returns
      * {@link #SERVICE_TYPE_EMERGENCY}
      *
@@ -841,6 +868,17 @@
     }
 
     /**
+     * Get the emergency Uniform Resource Names (URN), only valid if {@link #getServiceType}
+     * returns {@link #SERVICE_TYPE_EMERGENCY}.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    public List<String> getEmergencyUrns() {
+        return mEmergencyUrns;
+    }
+
+    /**
      * Get the emergency call routing, only valid if {@link #getServiceType} returns
      * {@link #SERVICE_TYPE_EMERGENCY}
      *
diff --git a/telephony/java/com/android/internal/telephony/IAns.aidl b/telephony/java/com/android/internal/telephony/IOns.aidl
similarity index 92%
rename from telephony/java/com/android/internal/telephony/IAns.aidl
rename to telephony/java/com/android/internal/telephony/IOns.aidl
index 98bcd41..d6779f1 100755
--- a/telephony/java/com/android/internal/telephony/IAns.aidl
+++ b/telephony/java/com/android/internal/telephony/IOns.aidl
@@ -18,13 +18,13 @@
 
 import android.telephony.AvailableNetworkInfo;
 
-interface IAns {
+interface IOns {
 
     /**
-    * Enable or disable Alternative Network service.
+    * Enable or disable Opportunistic Network service.
     *
     * This method should be called to enable or disable
-    * AlternativeNetwork service on the device.
+    * OpportunisticNetwork service on the device.
     *
     * <p>
     * Requires Permission:
@@ -38,9 +38,9 @@
     boolean setEnable(boolean enable, String callingPackage);
 
     /**
-     * is Alternative Network service enabled
+     * is Opportunistic Network service enabled
      *
-     * This method should be called to determine if the Alternative Network service is enabled
+     * This method should be called to determine if the Opportunistic Network service is enabled
     *
     * <p>
     * Requires Permission:
@@ -84,7 +84,7 @@
      * Update availability of a list of networks in the current location.
      *
      * This api should be called if the caller is aware of the availability of a network
-     * at the current location. This information will be used by AlternativeNetwork service
+     * at the current location. This information will be used by OpportunisticNetwork service
      * to decide to attach to the network. If an empty list is passed,
      * it is assumed that no network is available.
      * Requires that the calling app has carrier privileges on both primary and
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 9874f80..a508b06 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -18,6 +18,8 @@
 
 import android.Manifest.permission;
 import android.app.AppOpsManager;
+import android.app.role.RoleManager;
+import android.app.role.RoleManagerCallback;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -29,13 +31,12 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Debug;
 import android.os.Process;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.Rlog;
@@ -50,6 +51,10 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Class for managing the primary application that we will deliver SMS/MMS messages to
@@ -67,6 +72,7 @@
     private static final String SCHEME_SMSTO = "smsto";
     private static final String SCHEME_MMS = "mms";
     private static final String SCHEME_MMSTO = "mmsto";
+    private static final boolean DEBUG = false;
     private static final boolean DEBUG_MULTIUSER = false;
 
     private static final int[] DEFAULT_APP_EXCLUSIVE_APPOPS = {
@@ -240,7 +246,11 @@
 
         // Get the list of apps registered for SMS
         Intent intent = new Intent(Intents.SMS_DELIVER_ACTION);
-        List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
+        if (DEBUG) {
+            intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+        }
+        List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
 
         HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>();
@@ -266,7 +276,8 @@
         // Update any existing entries with mms receiver class
         intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
         intent.setDataAndType(null, "application/vnd.wap.mms-message");
-        List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
+        List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
         for (ResolveInfo resolveInfo : mmsReceivers) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -286,7 +297,8 @@
         // Update any existing entries with respond via message intent class.
         intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
                 Uri.fromParts(SCHEME_SMSTO, "", null));
-        List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, 0,
+        List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
         for (ResolveInfo resolveInfo : respondServices) {
             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -306,7 +318,8 @@
         // Update any existing entries with supports send to.
         intent = new Intent(Intent.ACTION_SENDTO,
                 Uri.fromParts(SCHEME_SMSTO, "", null));
-        List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, 0,
+        List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
         for (ResolveInfo resolveInfo : sendToActivities) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -323,7 +336,9 @@
         // Update any existing entries with the default sms changed handler.
         intent = new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
         List<ResolveInfo> smsAppChangedReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+                packageManager.queryBroadcastReceiversAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" +
                     smsAppChangedReceivers);
@@ -348,7 +363,9 @@
         // Update any existing entries with the external provider changed handler.
         intent = new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
         List<ResolveInfo> providerChangedReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+                packageManager.queryBroadcastReceiversAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" +
                     providerChangedReceivers);
@@ -373,7 +390,9 @@
         // Update any existing entries with the sim full handler.
         intent = new Intent(Intents.SIM_FULL_ACTION);
         List<ResolveInfo> simFullReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+                packageManager.queryBroadcastReceiversAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers="
                     + simFullReceivers);
@@ -406,7 +425,8 @@
             if (smsApplicationData != null) {
                 if (!smsApplicationData.isComplete()) {
                     Log.w(LOG_TAG, "Package " + packageName
-                            + " lacks required manifest declarations to be a default sms app");
+                            + " lacks required manifest declarations to be a default sms app: "
+                            + smsApplicationData);
                     receivers.remove(packageName);
                 }
             }
@@ -418,7 +438,7 @@
      * Checks to see if we have a valid installed SMS application for the specified package name
      * @return Data for the specified package name or null if there isn't one
      */
-    private static SmsApplicationData getApplicationForPackage(
+    public static SmsApplicationData getApplicationForPackage(
             Collection<SmsApplicationData> applications, String packageName) {
         if (packageName == null) {
             return null;
@@ -456,8 +476,7 @@
             Log.i(LOG_TAG, "getApplication userId=" + userId);
         }
         // Determine which application receives the broadcast
-        String defaultApplication = Settings.Secure.getStringForUser(context.getContentResolver(),
-                Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+        String defaultApplication = getDefaultSmsPackage(context, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplication defaultApp=" + defaultApplication);
         }
@@ -469,27 +488,6 @@
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplication appData=" + applicationData);
         }
-        // Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do
-        // this if the caller asked us to.
-        if (updateIfNeeded && applicationData == null) {
-            // Try to find the default SMS package for this device
-            Resources r = context.getResources();
-            String defaultPackage =
-                    r.getString(com.android.internal.R.string.default_sms_application);
-            applicationData = getApplicationForPackage(applications, defaultPackage);
-
-            if (applicationData == null) {
-                // Are there any applications?
-                if (applications.size() != 0) {
-                    applicationData = (SmsApplicationData)applications.toArray()[0];
-                }
-            }
-
-            // If we found a new default app, update the setting
-            if (applicationData != null) {
-                setDefaultApplicationInternal(applicationData.mPackageName, context, userId);
-            }
-        }
 
         // If we found a package, make sure AppOps permissions are set up correctly
         if (applicationData != null) {
@@ -513,7 +511,7 @@
                 // current SMS app will already be the preferred activity - but checking whether or
                 // not this is true is just as expensive as reconfiguring the preferred activity so
                 // we just reconfigure every time.
-                updateDefaultSmsApp(context, userId, applicationData);
+                defaultSmsAppChanged(context);
             }
         }
         if (DEBUG_MULTIUSER) {
@@ -522,16 +520,17 @@
         return applicationData;
     }
 
-    private static void updateDefaultSmsApp(Context context, int userId,
-            SmsApplicationData applicationData) {
+    private static String getDefaultSmsPackage(Context context, int userId) {
+        return context.getSystemService(RoleManager.class).getDefaultSmsPackage(userId);
+    }
+
+    /**
+     * Grants various permissions and appops on sms app change
+     */
+    private static void defaultSmsAppChanged(Context context) {
         PackageManager packageManager = context.getPackageManager();
         AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
 
-        // Configure this as the preferred activity for SENDTO sms/mms intents
-        configurePreferredActivity(packageManager, new ComponentName(
-                        applicationData.mPackageName, applicationData.mSendToClass),
-                userId);
-
         // Assign permission to special system apps
         assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
                 PHONE_PACKAGE_NAME);
@@ -603,8 +602,7 @@
         final UserHandle userHandle = UserHandle.of(userId);
 
         // Get old package name
-        String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
-                Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+        String oldPackageName = getDefaultSmsPackage(context, userId);
 
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldPackageName +
@@ -636,16 +634,29 @@
                 }
             }
 
-            // Update the secure setting.
-            Settings.Secure.putStringForUser(context.getContentResolver(),
-                    Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName,
-                    userId);
+            // Update the setting.
+            CompletableFuture<Void> res = new CompletableFuture<>();
+            context.getSystemService(RoleManager.class).addRoleHolderAsUser(
+                    RoleManager.ROLE_SMS, applicationData.mPackageName, UserHandle.of(userId),
+                    AsyncTask.THREAD_POOL_EXECUTOR, new RoleManagerCallback() {
+                        @Override
+                        public void onSuccess() {
+                            res.complete(null);
+                        }
 
-            // Allow relevant appops for the newly configured default SMS app.
-            setExclusiveAppops(applicationData.mPackageName, appOps, applicationData.mUid,
-                    AppOpsManager.MODE_ALLOWED);
+                        @Override
+                        public void onFailure() {
+                            res.completeExceptionally(new RuntimeException());
+                        }
+                    });
+            try {
+                res.get(5, TimeUnit.SECONDS);
+            } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                Log.e(LOG_TAG, "Exception while adding sms role holder " + applicationData, e);
+                return;
+            }
 
-            updateDefaultSmsApp(context, userId, applicationData);
+            defaultSmsAppChanged(context);
 
             if (DEBUG_MULTIUSER) {
                 Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 870a689..dd40d56 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -39,7 +39,7 @@
     oneway void switchToSubscription(int subscriptionId, String callingPackage,
         in PendingIntent callbackIntent);
     oneway void updateSubscriptionNickname(int subscriptionId, String nickname,
-        in PendingIntent callbackIntent);
+        String callingPackage, in PendingIntent callbackIntent);
     oneway void eraseSubscriptions(in PendingIntent callbackIntent);
     oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent);
 }
\ No newline at end of file
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 37158e5..e1d6e01 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -25,7 +25,8 @@
         "android.test.mock",
     ],
 
+    srcs_lib: "framework",
+    srcs_lib_whitelist_dirs: ["core/java"],
     srcs_lib_whitelist_pkgs: ["android"],
-    metalava_enabled: false,
     compile_dex: true,
 }
diff --git a/tests/PackageWatchdog/Android.mk b/tests/PackageWatchdog/Android.mk
new file mode 100644
index 0000000..b53f27d
--- /dev/null
+++ b/tests/PackageWatchdog/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# PackageWatchdogTest
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := PackageWatchdogTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    junit \
+    frameworks-base-testutils \
+    android-support-test \
+    services
+
+LOCAL_JAVA_LIBRARIES := \
+    android.test.runner
+
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/PackageWatchdog/AndroidManifest.xml b/tests/PackageWatchdog/AndroidManifest.xml
new file mode 100644
index 0000000..fa89528
--- /dev/null
+++ b/tests/PackageWatchdog/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?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.tests.packagewatchdog" >
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.tests.packagewatchdog"
+                     android:label="PackageWatchdog Test"/>
+</manifest>
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
new file mode 100644
index 0000000..ec07037
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.test.TestLooper;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+// TODO(zezeozue): Write test without using PackageWatchdog#getPackages. Just rely on
+// behavior of observers receiving crash notifications or not to determine if it's registered
+/**
+ * Test PackageWatchdog.
+ */
+public class PackageWatchdogTest {
+    private static final String APP_A = "com.package.a";
+    private static final String APP_B = "com.package.b";
+    private static final String OBSERVER_NAME_1 = "observer1";
+    private static final String OBSERVER_NAME_2 = "observer2";
+    private static final String OBSERVER_NAME_3 = "observer3";
+    private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
+    private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
+    private TestLooper mTestLooper;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mTestLooper.startAutoDispatch();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        new File(InstrumentationRegistry.getContext().getFilesDir(),
+                "package-watchdog.xml").delete();
+    }
+
+    /**
+     * Test registration, unregistration, package expiry and duration reduction
+     */
+    @Test
+    public void testRegistration() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+        TestObserver observer3 = new TestObserver(OBSERVER_NAME_3);
+
+        // Start observing for observer1 which will be unregistered
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+        // Start observing for observer2 which will expire
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+        // Start observing for observer3 which will have expiry duration reduced
+        watchdog.startObservingHealth(observer3, Arrays.asList(APP_A), LONG_DURATION);
+
+        // Verify packages observed at start
+        // 1
+        assertEquals(1, watchdog.getPackages(observer1).size());
+        assertTrue(watchdog.getPackages(observer1).contains(APP_A));
+        // 2
+        assertEquals(2, watchdog.getPackages(observer2).size());
+        assertTrue(watchdog.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog.getPackages(observer2).contains(APP_B));
+        // 3
+        assertEquals(1, watchdog.getPackages(observer3).size());
+        assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+        // Then unregister observer1
+        watchdog.unregisterHealthObserver(observer1);
+
+        // Verify observer2 and observer3 left
+        // 1
+        assertNull(watchdog.getPackages(observer1));
+        // 2
+        assertEquals(2, watchdog.getPackages(observer2).size());
+        assertTrue(watchdog.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog.getPackages(observer2).contains(APP_B));
+        // 3
+        assertEquals(1, watchdog.getPackages(observer3).size());
+        assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+        // Then advance time a little and run messages in Handlers so observer2 expires
+        Thread.sleep(SHORT_DURATION);
+        mTestLooper.dispatchAll();
+
+        // Verify observer3 left with reduced expiry duration
+        // 1
+        assertNull(watchdog.getPackages(observer1));
+        // 2
+        assertNull(watchdog.getPackages(observer2));
+        // 3
+        assertEquals(1, watchdog.getPackages(observer3).size());
+        assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+        // Then advance time some more and run messages in Handlers so observer3 expires
+        Thread.sleep(LONG_DURATION);
+        mTestLooper.dispatchAll();
+
+        // Verify observer3 expired
+        // 1
+        assertNull(watchdog.getPackages(observer1));
+        // 2
+        assertNull(watchdog.getPackages(observer2));
+        // 3
+        assertNull(watchdog.getPackages(observer3));
+    }
+
+    /**
+     * Test package observers are persisted and loaded on startup
+     */
+    @Test
+    public void testPersistence() throws Exception {
+        PackageWatchdog watchdog1 = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+        watchdog1.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog1.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+
+        // Verify 2 observers are registered and saved internally
+        // 1
+        assertEquals(1, watchdog1.getPackages(observer1).size());
+        assertTrue(watchdog1.getPackages(observer1).contains(APP_A));
+        // 2
+        assertEquals(2, watchdog1.getPackages(observer2).size());
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
+
+
+        // Then advance time and run IO Handler so file is saved
+        mTestLooper.dispatchAll();
+
+        // Then start a new watchdog
+        PackageWatchdog watchdog2 = createWatchdog();
+
+        // Verify the new watchdog loads observers on startup but nothing registered
+        assertEquals(0, watchdog2.getPackages(observer1).size());
+        assertEquals(0, watchdog2.getPackages(observer2).size());
+        // Verify random observer not saved returns null
+        assertNull(watchdog2.getPackages(new TestObserver(OBSERVER_NAME_3)));
+
+        // Then regiser observer1
+        watchdog2.registerHealthObserver(observer1);
+        watchdog2.registerHealthObserver(observer2);
+
+        // Verify 2 observers are registered after reload
+        // 1
+        assertEquals(1, watchdog1.getPackages(observer1).size());
+        assertTrue(watchdog1.getPackages(observer1).contains(APP_A));
+        // 2
+        assertEquals(2, watchdog1.getPackages(observer2).size());
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
+    }
+
+    /**
+     * Test package failure under threshold does not notify observers
+     */
+    @Test
+    public void testNoPackageFailureBeforeThreshold() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+        // Then fail APP_A below the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+
+        // Verify that observers are not notified
+        assertEquals(0, observer1.mFailedPackages.size());
+        assertEquals(0, observer2.mFailedPackages.size());
+    }
+
+    /**
+     * Test package failure and notifies all observer since none handles the failure
+     */
+    @Test
+    public void testPackageFailureNotifyAll() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+        // Start observing for observer1 and observer2 without handling failures
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+
+        // Then fail APP_A and APP_B above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A, APP_B});
+        }
+
+        // Verify all observers are notifed of all package failures
+        List<String> observer1Packages = observer1.mFailedPackages;
+        List<String> observer2Packages = observer2.mFailedPackages;
+        assertEquals(2, observer1Packages.size());
+        assertEquals(1, observer2Packages.size());
+        assertEquals(APP_A, observer1Packages.get(0));
+        assertEquals(APP_B, observer1Packages.get(1));
+        assertEquals(APP_A, observer2Packages.get(0));
+    }
+
+    /**
+     * Test package failure and notifies only one observer because it handles the failure
+     */
+    @Test
+    public void testPackageFailureNotifyOne() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, true /* shouldHandle */);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, true /* shouldHandle */);
+
+        // Start observing for observer1 and observer2 with failure handling
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+        // Then fail APP_A above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+
+        // Verify only one observer is notifed
+        assertEquals(1, observer1.mFailedPackages.size());
+        assertEquals(APP_A, observer1.mFailedPackages.get(0));
+        assertEquals(0, observer2.mFailedPackages.size());
+    }
+
+    private PackageWatchdog createWatchdog() {
+        return new PackageWatchdog(InstrumentationRegistry.getContext(),
+                mTestLooper.getLooper());
+    }
+
+    private static class TestObserver implements PackageHealthObserver {
+        private final String mName;
+        private boolean mShouldHandle;
+        final List<String> mFailedPackages = new ArrayList<>();
+
+        TestObserver(String name) {
+            mName = name;
+        }
+
+        TestObserver(String name, boolean shouldHandle) {
+            mName = name;
+            mShouldHandle = shouldHandle;
+        }
+
+        public boolean onHealthCheckFailed(String packageName) {
+            mFailedPackages.add(packageName);
+            return mShouldHandle;
+        }
+
+        public String getName() {
+            return mName;
+        }
+    }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 0ccfb19..77cd9d8 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -108,6 +108,10 @@
             }
 
             // The app should not be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is uninstalled and when the previously
+            // available rollback, if any, is removed.
+            Thread.sleep(1000);
             assertNull(rm.getAvailableRollback(TEST_APP_A));
             assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
 
@@ -125,6 +129,10 @@
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
             // The app should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
             assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
             RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
             assertNotNull(rollback);
@@ -182,6 +190,8 @@
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
+            // TODO: Test this with multi-package rollback, not just single
+            // package rollback.
             // Prep installation of TEST_APP_A
             RollbackTestUtils.uninstall(TEST_APP_A);
             RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -189,6 +199,10 @@
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
             // The app should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
             assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
             RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
             assertNotNull(rollback);
@@ -263,6 +277,10 @@
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
             // The app should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
             assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
             RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
             assertNotNull(rollback);
@@ -405,6 +423,10 @@
 
             // Both test apps should now be available for rollback, and the
             // targetPackage returned for rollback should be correct.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
             RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
             assertNotNull(rollbackA);
             assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName);
@@ -491,7 +513,7 @@
      * TODO: Stop ignoring this test once support for multi-package rollback
      * is implemented.
      */
-    @Ignore @Test
+    @Test
     public void testMultiPackage() throws Exception {
         try {
             RollbackTestUtils.adoptShellPermissionIdentity(
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 9d1edbf..f6f35fd 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -18,6 +18,7 @@
     mockito-target-minus-junit4 \
     platform-test-annotations \
     services.core \
+    services.ipmemorystore \
     services.net
 
 LOCAL_JAVA_LIBRARIES := \
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
new file mode 100644
index 0000000..eae9710
--- /dev/null
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.net;
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpMemoryStoreTest {
+    @Mock
+    Context mMockContext;
+    @Mock
+    IIpMemoryStore mMockService;
+    IpMemoryStore mStore;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mStore = new IpMemoryStore(mMockContext, mMockService);
+    }
+
+    @Test
+    public void testNetworkAttributes() {
+        // TODO : implement this
+    }
+
+    @Test
+    public void testPrivateData() {
+        // TODO : implement this
+    }
+
+    @Test
+    public void testFindL2Key() {
+        // TODO : implement this
+    }
+
+    @Test
+    public void testIsSameNetwork() {
+        // TODO : implement this
+    }
+
+}
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
new file mode 100644
index 0000000..a9f9758
--- /dev/null
+++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
@@ -0,0 +1,113 @@
+/*
+ * 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.net.ipmemorystore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.Collections;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ParcelableTests {
+    @Test
+    public void testNetworkAttributesParceling() throws Exception {
+        final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
+        NetworkAttributes in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+        builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        // groupHint stays null this time around
+        builder.setDnsAddresses(Collections.emptyList());
+        builder.setMtu(18);
+        in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+        builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
+        builder.setGroupHint("groupHint");
+        builder.setDnsAddresses(Arrays.asList(
+                InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
+                InetAddress.getByName("6.7.8.9")));
+        builder.setMtu(1_000_000);
+        in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+        builder.setMtu(null);
+        in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+    }
+
+    @Test
+    public void testPrivateDataParceling() throws Exception {
+        final Blob in = new Blob();
+        in.data = new byte[] {89, 111, 108, 111};
+        final Blob out = parcelingRoundTrip(in);
+        // Object.equals on byte[] tests the references
+        assertEquals(in.data.length, out.data.length);
+        assertTrue(Arrays.equals(in.data, out.data));
+    }
+
+    @Test
+    public void testSameL3NetworkResponseParceling() throws Exception {
+        final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
+        parcelable.l2Key1 = "key 1";
+        parcelable.l2Key2 = "key 2";
+        parcelable.confidence = 0.43f;
+
+        final SameL3NetworkResponse in = new SameL3NetworkResponse(parcelable);
+        assertEquals("key 1", in.l2Key1);
+        assertEquals("key 2", in.l2Key2);
+        assertEquals(0.43f, in.confidence, 0.01f /* delta */);
+
+        final SameL3NetworkResponse out =
+                new SameL3NetworkResponse(parcelingRoundTrip(in.toParcelable()));
+
+        assertEquals(in, out);
+        assertEquals(in.l2Key1, out.l2Key1);
+        assertEquals(in.l2Key2, out.l2Key2);
+        assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
+    }
+
+    private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
+        final Parcel p = Parcel.obtain();
+        in.writeToParcel(p, /* flags */ 0);
+        p.setDataPosition(0);
+        final byte[] marshalledData = p.marshall();
+        p.recycle();
+
+        final Parcel q = Parcel.obtain();
+        q.unmarshall(marshalledData, 0, marshalledData.length);
+        q.setDataPosition(0);
+
+        final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
+                in.getClass().getField("CREATOR").get(null); // static object, so null receiver
+        final T unmarshalled = (T) creator.createFromParcel(q);
+        q.recycle();
+        return unmarshalled;
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 71529fd..bf39644 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -26,6 +26,8 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
 import static android.net.ConnectivityManager.TYPE_NONE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
@@ -69,17 +71,19 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -89,7 +93,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
-import android.net.CaptivePortal;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.ConnectivityManager.PacketKeepalive;
@@ -97,6 +100,8 @@
 import android.net.ConnectivityManager.TooManyRequestsException;
 import android.net.ConnectivityThread;
 import android.net.INetd;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
@@ -114,12 +119,14 @@
 import android.net.NetworkMisc;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.StringNetworkSpecifier;
 import android.net.UidRange;
-import android.net.captiveportal.CaptivePortalProbeResult;
 import android.net.metrics.IpConnectivityLog;
+import android.net.shared.NetworkMonitorUtils;
+import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.os.ConditionVariable;
 import android.os.Handler;
@@ -148,12 +155,9 @@
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.connectivity.ConnectivityConstants;
 import com.android.server.connectivity.DefaultNetworkMetrics;
-import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.Nat464Xlat;
-import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.NetworkPinner;
@@ -168,6 +172,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
@@ -230,6 +235,7 @@
     @Mock INetworkStatsService mStatsService;
     @Mock INetworkPolicyManager mNpm;
     @Mock INetd mMockNetd;
+    @Mock NetworkStack mNetworkStack;
 
     private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
 
@@ -299,6 +305,7 @@
         public Object getSystemService(String name) {
             if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
             if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
+            if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
             return super.getSystemService(name);
         }
 
@@ -386,7 +393,7 @@
     }
 
     private class MockNetworkAgent {
-        private final WrappedNetworkMonitor mWrappedNetworkMonitor;
+        private final INetworkMonitor mNetworkMonitor;
         private final NetworkInfo mNetworkInfo;
         private final NetworkCapabilities mNetworkCapabilities;
         private final HandlerThread mHandlerThread;
@@ -402,6 +409,26 @@
         // mNetworkStatusReceived.
         private String mRedirectUrl;
 
+        private INetworkMonitorCallbacks mNmCallbacks;
+        private int mNmValidationResult = NETWORK_TEST_RESULT_INVALID;
+        private String mNmValidationRedirectUrl = null;
+        private boolean mNmProvNotificationRequested = false;
+
+        void setNetworkValid() {
+            mNmValidationResult = NETWORK_TEST_RESULT_VALID;
+            mNmValidationRedirectUrl = null;
+        }
+
+        void setNetworkInvalid() {
+            mNmValidationResult = NETWORK_TEST_RESULT_INVALID;
+            mNmValidationRedirectUrl = null;
+        }
+
+        void setNetworkPortal(String redirectUrl) {
+            setNetworkInvalid();
+            mNmValidationRedirectUrl = redirectUrl;
+        }
+
         MockNetworkAgent(int transport) {
             this(transport, new LinkProperties());
         }
@@ -434,6 +461,29 @@
             }
             mHandlerThread = new HandlerThread("Mock-" + typeName);
             mHandlerThread.start();
+
+            mNetworkMonitor = mock(INetworkMonitor.class);
+            final Answer validateAnswer = inv -> {
+                new Thread(this::onValidationRequested).start();
+                return null;
+            };
+
+            try {
+                doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
+                doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
+            } catch (RemoteException e) {
+                fail(e.getMessage());
+            }
+
+            final ArgumentCaptor<Network> nmNetworkCaptor =
+                    ArgumentCaptor.forClass(Network.class);
+            final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor =
+                    ArgumentCaptor.forClass(INetworkMonitorCallbacks.class);
+            doNothing().when(mNetworkStack).makeNetworkMonitor(
+                    nmNetworkCaptor.capture(),
+                    any() /* name */,
+                    nmCbCaptor.capture());
+
             mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
                     "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
                     linkProperties, mScore, new NetworkMisc()) {
@@ -465,10 +515,40 @@
                     mPreventReconnectReceived.open();
                 }
             };
+
+            assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
+            mNmCallbacks = nmCbCaptor.getValue();
+
+            try {
+                mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
+            } catch (RemoteException e) {
+                fail(e.getMessage());
+            }
+
             // Waits for the NetworkAgent to be registered, which includes the creation of the
             // NetworkMonitor.
             waitForIdle();
-            mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
+        }
+
+        private void onValidationRequested() {
+            try {
+                if (mNmProvNotificationRequested
+                        && mNmValidationResult == NETWORK_TEST_RESULT_VALID) {
+                    mNmCallbacks.hideProvisioningNotification();
+                    mNmProvNotificationRequested = false;
+                }
+
+                mNmCallbacks.notifyNetworkTested(
+                        mNmValidationResult, mNmValidationRedirectUrl);
+
+                if (mNmValidationRedirectUrl != null) {
+                    mNmCallbacks.showProvisioningNotification(
+                            "test_provisioning_notif_action");
+                    mNmProvNotificationRequested = true;
+                }
+            } catch (RemoteException e) {
+                fail(e.getMessage());
+            }
         }
 
         public void adjustScore(int change) {
@@ -539,7 +619,7 @@
             NetworkCallback callback = null;
             final ConditionVariable validatedCv = new ConditionVariable();
             if (validated) {
-                mWrappedNetworkMonitor.gen204ProbeResult = 204;
+                setNetworkValid();
                 NetworkRequest request = new NetworkRequest.Builder()
                         .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
                         .clearCapabilities()
@@ -564,15 +644,14 @@
             if (validated) {
                 // Wait for network to validate.
                 waitFor(validatedCv);
-                mWrappedNetworkMonitor.gen204ProbeResult = 500;
+                setNetworkInvalid();
             }
 
             if (callback != null) mCm.unregisterNetworkCallback(callback);
         }
 
         public void connectWithCaptivePortal(String redirectUrl) {
-            mWrappedNetworkMonitor.gen204ProbeResult = 200;
-            mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
+            setNetworkPortal(redirectUrl);
             connect(false);
         }
 
@@ -603,10 +682,6 @@
             return mDisconnected;
         }
 
-        public WrappedNetworkMonitor getWrappedNetworkMonitor() {
-            return mWrappedNetworkMonitor;
-        }
-
         public void sendLinkProperties(LinkProperties lp) {
             mNetworkAgent.sendLinkProperties(lp);
         }
@@ -880,28 +955,6 @@
         }
     }
 
-    // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
-    private class WrappedNetworkMonitor extends NetworkMonitor {
-        public final Handler connectivityHandler;
-        // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
-        public int gen204ProbeResult = 500;
-        public String gen204ProbeRedirectUrl = null;
-
-        public WrappedNetworkMonitor(Context context, Handler handler,
-                NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
-                IpConnectivityLog log) {
-            super(context, handler, networkAgentInfo, defaultRequest, log,
-                    NetworkMonitor.Dependencies.DEFAULT);
-            connectivityHandler = handler;
-        }
-
-        @Override
-        protected CaptivePortalProbeResult isCaptivePortal() {
-            if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
-            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
-        }
-    }
-
     private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
         public volatile boolean configRestrictsAvoidBadWifi;
         public volatile int configMeteredMultipathPreference;
@@ -923,7 +976,6 @@
 
     private class WrappedConnectivityService extends ConnectivityService {
         public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
-        private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
         private MockableSystemProperties mSystemProperties;
 
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
@@ -971,15 +1023,6 @@
             }
         }
 
-        @Override
-        public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
-                NetworkAgentInfo nai, NetworkRequest defaultRequest) {
-            final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(
-                    context, handler, nai, defaultRequest, mock(IpConnectivityLog.class));
-            mLastCreatedNetworkMonitor = monitor;
-            return monitor;
-        }
-
         public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
             return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
         }
@@ -1017,10 +1060,6 @@
         protected void registerNetdEventCallback() {
         }
 
-        public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
-            return mLastCreatedNetworkMonitor;
-        }
-
         public void mockVpn(int uid) {
             synchronized (mVpns) {
                 int userId = UserHandle.getUserId(uid);
@@ -2439,7 +2478,7 @@
 
         // Make captive portal disappear then revalidate.
         // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
+        mWiFiNetworkAgent.setNetworkValid();
         mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
@@ -2448,13 +2487,13 @@
 
         // Break network connectivity.
         // Expect NET_CAPABILITY_VALIDATED onLost callback.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
+        mWiFiNetworkAgent.setNetworkInvalid();
         mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
         validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
     }
 
     @Test
-    public void testCaptivePortalApp() {
+    public void testCaptivePortalApp() throws RemoteException {
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
                 .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
@@ -2477,21 +2516,19 @@
         mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
 
         // Turn into a captive portal.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 302;
+        mWiFiNetworkAgent.setNetworkPortal("http://example.com");
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
-        // Check that startCaptivePortalApp sends the expected intent.
+        // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
         mCm.startCaptivePortalApp(wifiNetwork);
-        Intent intent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
-        assertEquals(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction());
-        assertEquals(wifiNetwork, intent.getExtra(ConnectivityManager.EXTRA_NETWORK));
+        verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
+                .launchCaptivePortalApp();
 
-        // Have the app report that the captive portal is dismissed, and check that we revalidate.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
-        CaptivePortal c = (CaptivePortal) intent.getExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
-        c.reportCaptivePortalDismissed();
+        // Report that the captive portal is dismissed, and check that callbacks are fired
+        mWiFiNetworkAgent.setNetworkValid();
+        mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
         validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
@@ -2524,20 +2561,6 @@
         waitFor(avoidCv);
 
         assertNoCallbacks(captivePortalCallback, validatedCallback);
-
-        // Now test ignore mode.
-        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
-
-        // Bring up a network with a captive portal.
-        // Since we're ignoring captive portals, the network will validate.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        String secondRedirectUrl = "http://example.com/secondPath";
-        mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
-
-        // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
-        validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
-        // But there should be no CaptivePortal callback.
-        captivePortalCallback.assertNoCallback();
     }
 
     private NetworkRequest.Builder newWifiRequestBuilder() {
@@ -3169,7 +3192,7 @@
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+        mWiFiNetworkAgent.setNetworkInvalid();
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -3213,7 +3236,7 @@
         wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi and expect the dialog to appear.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+        mWiFiNetworkAgent.setNetworkInvalid();
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -4002,11 +4025,9 @@
         final String TLS_SERVER6 = "2001:db8:53::53";
         final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) };
         final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 };
-        final Handler h = mCellNetworkAgent.getWrappedNetworkMonitor().connectivityHandler;
-        h.sendMessage(h.obtainMessage(
-                NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED, 0,
-                mCellNetworkAgent.getNetwork().netId,
-                new DnsManager.PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS)));
+        mCellNetworkAgent.mNmCallbacks.notifyPrivateDnsConfigResolved(
+                new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
+
         waitForIdle();
         verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
@@ -4294,6 +4315,12 @@
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.setUids(ranges);
+        // VPN networks do not satisfy the default request and are automatically validated
+        // by NetworkMonitor
+        assertFalse(NetworkMonitorUtils.isValidationRequired(
+                mCm.getDefaultRequest().networkCapabilities, vpnNetworkAgent.mNetworkCapabilities));
+        vpnNetworkAgent.setNetworkValid();
+
         vpnNetworkAgent.connect(false);
         mMockVpn.connect();
 
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 01b468a..38322e9 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -17,7 +17,6 @@
 package com.android.server.connectivity;
 
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
@@ -29,13 +28,13 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
-import android.content.ContentResolver;
 import android.content.Context;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.RouteInfo;
+import android.net.shared.PrivateDnsConfig;
 import android.os.INetworkManagementService;
 import android.provider.Settings;
 import android.support.test.filters.SmallTest;
@@ -43,18 +42,16 @@
 import android.test.mock.MockContentResolver;
 
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
-import com.android.server.connectivity.MockableSystemProperties;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.net.InetAddress;
 import java.util.Arrays;
 
-import org.junit.runner.RunWith;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
 /**
  * Tests for {@link DnsManager}.
  *
@@ -133,7 +130,7 @@
                 PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
         Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
         mDnsManager.updatePrivateDns(new Network(TEST_NETID),
-                new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] {
+                new PrivateDnsConfig("strictmode.com", new InetAddress[] {
                     InetAddress.parseNumericAddress("6.6.6.6"),
                     InetAddress.parseNumericAddress("2001:db8:66:66::1")
                     }));
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 354cf2f..4c52d81 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -23,10 +23,10 @@
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.reset;
 
 import android.app.PendingIntent;
 import android.content.Context;
@@ -36,18 +36,18 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkMisc;
-import android.support.test.runner.AndroidJUnit4;
+import android.net.NetworkStack;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateUtils;
 
 import com.android.internal.R;
 import com.android.server.ConnectivityService;
-import com.android.server.connectivity.NetworkNotificationManager;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 
-import org.junit.runner.RunWith;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -70,13 +70,16 @@
     @Mock NetworkMisc mMisc;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
+    @Mock NetworkStack mNetworkStack;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mCtx.getResources()).thenReturn(mResources);
         when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
-        when(mConnService.createNetworkMonitor(any(), any(), any(), any())).thenReturn(null);
+        when(mCtx.getSystemServiceName(NetworkStack.class))
+                .thenReturn(Context.NETWORK_STACK_SERVICE);
+        when(mCtx.getSystemService(Context.NETWORK_STACK_SERVICE)).thenReturn(mNetworkStack);
 
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
     }
@@ -349,7 +352,7 @@
         caps.addCapability(0);
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
-                caps, 50, mCtx, null, mMisc, null, mConnService);
+                caps, 50, mCtx, null, mMisc, mConnService);
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
new file mode 100644
index 0000000..859a54d
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.ipmemorystore;
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unit tests for {@link IpMemoryStoreServiceTest}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IpMemoryStoreServiceTest {
+    @Mock
+    Context mMockContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testNetworkAttributes() {
+        final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+        // TODO : implement this
+    }
+
+    @Test
+    public void testPrivateData() {
+        final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+        // TODO : implement this
+    }
+
+    @Test
+    public void testFindL2Key() {
+        final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+        // TODO : implement this
+    }
+
+    @Test
+    public void testIsSameNetwork() {
+        final IpMemoryStoreService service = new IpMemoryStoreService(mMockContext);
+        // TODO : implement this
+    }
+}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index c42a888..0580df6 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -58,6 +58,7 @@
         "libprotobuf-cpp-lite",
         "libz",
     ],
+    stl: "libc++_static",
     group_static_libs: true,
 }
 
diff --git a/tools/bit/command.h b/tools/bit/command.h
index fb44900..dd7103e 100644
--- a/tools/bit/command.h
+++ b/tools/bit/command.h
@@ -25,7 +25,7 @@
 
 struct Command
 {
-    Command(const string& prog);
+    explicit Command(const string& prog);
     ~Command();
 
     void AddArg(const string& arg);
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 9968bda..4491a85 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -67,7 +67,7 @@
         case JAVA_TYPE_STRING:
             return "char const*";
         case JAVA_TYPE_BYTE_ARRAY:
-            return "char const*";
+            return "const BytesField&";
         default:
             return "UNKNOWN";
     }
@@ -270,10 +270,6 @@
                                  chainField.name.c_str(), chainField.name.c_str());
                     }
                 }
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out, ", %s arg%d, size_t arg%d_length",
-                        cpp_type_name(*arg), argIndex, argIndex);
-
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                 fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
                              "const std::map<int, int64_t>& arg%d_2, "
@@ -355,7 +351,8 @@
                     fprintf(out, "    event.end();\n\n");
             } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
                 fprintf(out,
-                        "    event.AppendCharArray(arg%d, arg%d_length);\n",
+                        "    event.AppendCharArray(arg%d.arg, "
+                        "arg%d.arg_length);\n",
                         argIndex, argIndex);
             } else {
                 if (*arg == JAVA_TYPE_STRING) {
@@ -397,10 +394,6 @@
                                 chainField.name.c_str(), chainField.name.c_str());
                    }
                }
-           } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-               fprintf(out, ", %s arg%d, size_t arg%d_length",
-                       cpp_type_name(*arg), argIndex, argIndex);
-
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out,
                        ", const std::map<int, int32_t>& arg%d_1, "
@@ -434,8 +427,6 @@
                                 chainField.name.c_str(), chainField.name.c_str());
                    }
                }
-           } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-               fprintf(out, ", arg%d, arg%d_length", argIndex, argIndex);
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
                        argIndex, argIndex, argIndex);
@@ -494,7 +485,14 @@
                 fprintf(out, "        arg%d = \"\";\n", argIndex);
                 fprintf(out, "    }\n");
             }
-            fprintf(out, "    event << arg%d;\n", argIndex);
+            if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out,
+                        "    event.AppendCharArray(arg%d.arg, "
+                        "arg%d.arg_length);",
+                        argIndex, argIndex);
+            } else {
+                fprintf(out, "    event << arg%d;\n", argIndex);
+            }
             if (argIndex == 2) {
                 fprintf(out, "    event.end();\n\n");
                 fprintf(out, "    event.end();\n\n");
@@ -577,7 +575,9 @@
 static void write_cpp_usage(
     FILE* out, const string& method_name, const string& atom_code_name,
     const AtomDecl& atom, const AtomDecl &attributionDecl) {
-    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
+    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(),
+            atom_code_name.c_str());
+
     for (vector<AtomField>::const_iterator field = atom.fields.begin();
             field != atom.fields.end(); field++) {
         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -601,11 +601,6 @@
                          field->name.c_str(),
                          field->name.c_str(),
                          field->name.c_str());
-        } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
-            fprintf(out, ", %s %s, size_t %s_length",
-                    cpp_type_name(field->javaType), field->name.c_str(),
-                    field->name.c_str());
-
         } else {
             fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
         }
@@ -639,9 +634,6 @@
                              "const std::map<int, char const*>& arg%d_3, "
                              "const std::map<int, float>& arg%d_4",
                              argIndex, argIndex, argIndex, argIndex);
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out, ", %s arg%d, size_t arg%d_length",
-                        cpp_type_name(*arg), argIndex, argIndex);
             } else {
                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
             }
@@ -708,6 +700,15 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
+    fprintf(out, "struct BytesField {\n");
+    fprintf(out,
+            "  BytesField(char const* array, size_t len) : arg(array), "
+            "arg_length(len) {}\n");
+    fprintf(out, "  char const* arg;\n");
+    fprintf(out, "  size_t arg_length;\n");
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
     fprintf(out, "struct StateAtomFieldOptions {\n");
     fprintf(out, "  std::vector<int> primaryFields;\n");
     fprintf(out, "  int exclusiveField;\n");
@@ -1183,6 +1184,11 @@
                 fprintf(out, "        str%d = NULL;\n", argIndex);
                 fprintf(out, "    }\n");
 
+                fprintf(out,
+                        "    android::util::BytesField bytesField%d(str%d, "
+                        "str%d_length);",
+                        argIndex, argIndex, argIndex);
+
             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 hadStringOrChain = true;
                 for (auto chainField : attributionDecl.fields) {
@@ -1240,7 +1246,8 @@
 
         // stats_write call
         argIndex = 1;
-        fprintf(out, "\n    int ret =  android::util::%s(code", cpp_method_name.c_str());
+        fprintf(out, "\n    int ret =  android::util::%s(code",
+                cpp_method_name.c_str());
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -1255,16 +1262,12 @@
                 }
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                 fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out, ", bytesField%d", argIndex);
             } else {
-                const char* argName = (*arg == JAVA_TYPE_STRING ||
-                                       *arg == JAVA_TYPE_BYTE_ARRAY)
-                                              ? "str"
-                                              : "arg";
+                const char* argName =
+                        (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
                 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
-
-                if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                    fprintf(out, ", %s%d_length", argName, argIndex);
-                }
             }
             argIndex++;
         }
diff --git a/tools/streaming_proto/Errors.h b/tools/streaming_proto/Errors.h
index f14bbfd..bddd981 100644
--- a/tools/streaming_proto/Errors.h
+++ b/tools/streaming_proto/Errors.h
@@ -11,7 +11,7 @@
 struct Error
 {
     Error();
-    explicit Error(const Error& that);
+    Error(const Error& that);
     Error(const string& filename, int lineno, const char* message);
 
     string filename;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a809cad..28dd9b4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -27,7 +27,6 @@
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
-import android.net.wifi.WifiInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -491,7 +490,7 @@
      * The set of group management ciphers supported by this configuration.
      * See {@link GroupMgmtCipher} for descriptions of the values.
      */
-    public BitSet allowedGroupMgmtCiphers;
+    public BitSet allowedGroupManagementCiphers;
     /**
      * The set of SuiteB ciphers supported by this configuration.
      * To be used for WPA3-Enterprise mode.
@@ -1642,7 +1641,7 @@
         allowedAuthAlgorithms = new BitSet();
         allowedPairwiseCiphers = new BitSet();
         allowedGroupCiphers = new BitSet();
-        allowedGroupMgmtCiphers = new BitSet();
+        allowedGroupManagementCiphers = new BitSet();
         allowedSuiteBCiphers = new BitSet();
         wepKeys = new String[4];
         for (int i = 0; i < wepKeys.length; i++) {
@@ -1835,8 +1834,8 @@
         }
         sbuf.append('\n');
         sbuf.append(" GroupMgmtCiphers:");
-        for (int gmc = 0; gmc < this.allowedGroupMgmtCiphers.size(); gmc++) {
-            if (this.allowedGroupMgmtCiphers.get(gmc)) {
+        for (int gmc = 0; gmc < this.allowedGroupManagementCiphers.size(); gmc++) {
+            if (this.allowedGroupManagementCiphers.get(gmc)) {
                 sbuf.append(" ");
                 if (gmc < GroupMgmtCipher.strings.length) {
                     sbuf.append(GroupMgmtCipher.strings[gmc]);
@@ -2235,7 +2234,7 @@
             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
-            allowedGroupMgmtCiphers    = (BitSet) source.allowedGroupMgmtCiphers.clone();
+            allowedGroupManagementCiphers = (BitSet) source.allowedGroupManagementCiphers.clone();
             allowedSuiteBCiphers    = (BitSet) source.allowedSuiteBCiphers.clone();
             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
 
@@ -2317,7 +2316,7 @@
         writeBitSet(dest, allowedAuthAlgorithms);
         writeBitSet(dest, allowedPairwiseCiphers);
         writeBitSet(dest, allowedGroupCiphers);
-        writeBitSet(dest, allowedGroupMgmtCiphers);
+        writeBitSet(dest, allowedGroupManagementCiphers);
         writeBitSet(dest, allowedSuiteBCiphers);
 
         dest.writeParcelable(enterpriseConfig, flags);
@@ -2389,7 +2388,7 @@
                 config.allowedAuthAlgorithms  = readBitSet(in);
                 config.allowedPairwiseCiphers = readBitSet(in);
                 config.allowedGroupCiphers    = readBitSet(in);
-                config.allowedGroupMgmtCiphers = readBitSet(in);
+                config.allowedGroupManagementCiphers = readBitSet(in);
                 config.allowedSuiteBCiphers   = readBitSet(in);
 
                 config.enterpriseConfig = in.readParcelable(null);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b265c40..517bf3b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -189,6 +189,7 @@
      */
     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
 
+    /** @hide */
     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
@@ -234,6 +235,12 @@
     @SystemApi
     public static final int WIFI_CREDENTIAL_FORGOT = 1;
 
+    /** @hide */
+    public static final int PASSPOINT_HOME_NETWORK = 0;
+
+    /** @hide */
+    public static final int PASSPOINT_ROAMING_NETWORK = 1;
+
     /**
      * Broadcast intent action indicating that a Passpoint provider icon has been received.
      *
@@ -1207,26 +1214,30 @@
      * match the ScanResult.
      *
      * @param scanResults a list of scanResult that represents the BSSID
-     * @return List that consists of {@link WifiConfiguration} and corresponding scanResults.
+     * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
+     * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public List<Pair<WifiConfiguration, List<ScanResult>>> getAllMatchingWifiConfigs(
+    public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
             @NonNull List<ScanResult> scanResults) {
-        List<Pair<WifiConfiguration, List<ScanResult>>> configs = new ArrayList<>();
+        List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
         try {
-            Map<String, List<ScanResult>> results = mService.getAllMatchingFqdnsForScanResults(
-                    scanResults);
+            Map<String, Map<Integer, List<ScanResult>>> results =
+                    mService.getAllMatchingFqdnsForScanResults(
+                            scanResults);
             if (results.isEmpty()) {
                 return configs;
             }
             List<WifiConfiguration> wifiConfigurations =
-                    mService.getWifiConfigsForPasspointProfiles(new ArrayList<>(results.keySet()));
+                    mService.getWifiConfigsForPasspointProfiles(
+                            new ArrayList<>(results.keySet()));
             for (WifiConfiguration configuration : wifiConfigurations) {
-                List<ScanResult> scanResultList = results.get(configuration.FQDN);
-                if (scanResultList != null) {
-                    configs.add(Pair.create(configuration, scanResultList));
+                Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
+                        configuration.FQDN);
+                if (scanResultsPerNetworkType != null) {
+                    configs.add(Pair.create(configuration, scanResultsPerNetworkType));
                 }
             }
         } catch (RemoteException e) {
@@ -1642,7 +1653,7 @@
      * suggestion back using this API.</li>
      *
      * @param networkSuggestions List of network suggestions provided by the app.
-     * @return Status code corresponding to the values in {@link NetworkSuggestionsStatusCode}.
+     * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
      * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
      * @throws {@link SecurityException} if the caller is missing required permissions.
      */
@@ -1663,8 +1674,7 @@
      *
      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
      *                           to remove all the previous suggestions provided by the app.
-     * @return Status code corresponding to the values in
-     * {@link NetworkSuggestionsStatusCode}.
+     * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
      * Any matching suggestions are removed from the device and will not be considered for any
      * further connection attempts.
      */
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
index f73b9e5..ecee5ff 100644
--- a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -412,7 +412,7 @@
             configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
             configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
             // TODO (b/113878056): Verify these params once we verify SuiteB configuration.
-            configuration.allowedGroupMgmtCiphers.set(
+            configuration.allowedGroupManagementCiphers.set(
                     WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
             configuration.allowedSuiteBCiphers.set(
                     WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 6631fa8..f931ad2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -223,7 +223,8 @@
         private MacAddress mDeviceAddress = MAC_ANY_ADDRESS;
         private String mNetworkName = "";
         private String mPassphrase = "";
-        private int mGroupOwnerBand = GROUP_OWNER_BAND_AUTO;
+        private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
+        private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
         private int mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
 
         /**
@@ -285,22 +286,84 @@
         }
 
         /**
-         * Specify the band to use for creating the group. This method only applies when
-         * creating a group as Group Owner using {@link WifiP2pManager#createGroup}.
-         * The band should be {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ},
-         * or allow the system to pick the band by specifying {@link #GROUP_OWNER_BAND_AUTO}.
+         * Specify the band to use for creating the group or joining the group. The band should
+         * be {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ} or
+         * {@link #GROUP_OWNER_BAND_AUTO}.
+         * <p>
+         * When creating a group as Group Owner using {@link
+         * WifiP2pManager#createGroup(WifiP2pManager.Channel,
+         * WifiP2pConfig, WifiP2pManager.ActionListener)},
+         * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to pick the operating
+         * frequency from all supported bands.
+         * Specifying {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ}
+         * only allows the system to pick the operating frequency in the specified band.
          * If the Group Owner cannot create a group in the specified band, the operation will fail.
          * <p>
+         * When joining a group as Group Client using {@link
+         * WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
+         * WifiP2pManager.ActionListener)},
+         * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to scan all supported
+         * frequencies to find the desired group. Specifying {@link #GROUP_OWNER_BAND_2GHZ} or
+         * {@link #GROUP_OWNER_BAND_5GHZ} only allows the system to scan the specified band.
+         * <p>
+         *     {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
+         *     mutually exclusive. Setting operating band and frequency both is invalid.
+         * <p>
          *     Optional. {@link #GROUP_OWNER_BAND_AUTO} by default.
          *
-         * @param band the required band of group owner.
+         * @param band the operating band of the group.
          *             This should be one of {@link #GROUP_OWNER_BAND_AUTO},
          *             {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ}.
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder setGroupOwnerBand(int band) {
-            mGroupOwnerBand = band;
+        public Builder setGroupOperatingBand(@GroupOwnerBandType int band) {
+            switch (band) {
+                case GROUP_OWNER_BAND_AUTO:
+                case GROUP_OWNER_BAND_2GHZ:
+                case GROUP_OWNER_BAND_5GHZ:
+                    mGroupOperatingBand = band;
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                        "Invalid constant for the group operating band!");
+            }
+            return this;
+        }
+
+        /**
+         * Specify the frequency to use for creating the group or joining the group.
+         * <p>
+         * When creating a group as Group Owner using {@link WifiP2pManager#createGroup(
+         * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
+         * specifying a frequency only allows the system to pick the specified frequency.
+         * If the Group Owner cannot create a group at the specified frequency,
+         * the operation will fail.
+         * When not specifying a frequency, it allows the system to pick operating frequency
+         * from all supported bands.
+         * <p>
+         * When joining a group as Group Client using {@link WifiP2pManager#connect(
+         * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
+         * specifying a frequency only allows the system to scan the specified frequency.
+         * If the frequency is not supported or invalid, the operation will fail.
+         * When not specifying a frequency, it allows the system to scan all supported
+         * frequencies to find the desired group.
+         * <p>
+         *     {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
+         *     mutually exclusive. Setting operating band and frequency both is invalid.
+         * <p>
+         *     Optional. 0 by default.
+         *
+         * @param frequency the operating frequency of the group.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setGroupOperatingFrequency(int frequency) {
+            if (frequency < 0) {
+                throw new IllegalArgumentException(
+                    "Invalid group operating frequency!");
+            }
+            mGroupOperatingFrequency = frequency;
             return this;
         }
 
@@ -337,11 +400,21 @@
                         "passphrase must be non-empty.");
             }
 
+            if (mGroupOperatingFrequency > 0 && mGroupOperatingBand > 0) {
+                throw new IllegalStateException(
+                        "Preferred frequency and band are mutually exclusive.");
+            }
+
             WifiP2pConfig config = new WifiP2pConfig();
             config.deviceAddress = mDeviceAddress.toString();
             config.networkName = mNetworkName;
             config.passphrase = mPassphrase;
-            config.groupOwnerBand = mGroupOwnerBand;
+            config.groupOwnerBand = GROUP_OWNER_BAND_AUTO;
+            if (mGroupOperatingFrequency > 0) {
+                config.groupOwnerBand = mGroupOperatingFrequency;
+            } else if (mGroupOperatingBand > 0) {
+                config.groupOwnerBand = mGroupOperatingBand;
+            }
             config.netId = mNetId;
             return config;
         }
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 4e29dd1..2c96c05 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -89,7 +89,7 @@
     }
 
     @Override
-    public Map<String, List<ScanResult>> getAllMatchingFqdnsForScanResults(
+    public Map<String, Map<Integer, List<ScanResult>>> getAllMatchingFqdnsForScanResults(
             List<ScanResult> scanResults) {
         throw new UnsupportedOperationException();
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
index 83627ad..dd6e2c9 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -518,7 +518,7 @@
                 .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
         assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
                 .get(WifiConfiguration.GroupCipher.GCMP_256));
-        assertTrue(suggestion.wifiConfiguration.allowedGroupMgmtCiphers
+        assertTrue(suggestion.wifiConfiguration.allowedGroupManagementCiphers
                 .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
         assertTrue(suggestion.wifiConfiguration.allowedSuiteBCiphers
                 .get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA));