Merge "Handle onBindingDied in AbstractRemoteService" into qt-dev
diff --git a/Android.bp b/Android.bp
index 21054dd..6a85f62 100644
--- a/Android.bp
+++ b/Android.bp
@@ -161,6 +161,7 @@
         ":libcamera_client_framework_aidl",
         "core/java/android/hardware/IConsumerIrService.aidl",
         "core/java/android/hardware/ISerialManager.aidl",
+        "core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl",
         "core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl",
         "core/java/android/hardware/biometrics/IBiometricService.aidl",
         "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
diff --git a/api/current.txt b/api/current.txt
index 5997043..01edc71 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5335,6 +5335,7 @@
     field public static final String EXTRA_TITLE = "android.title";
     field public static final String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_BUBBLE = 4096; // 0x1000
     field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
     field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
     field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
@@ -5480,7 +5481,8 @@
     method @DimenRes public int getDesiredHeightResId();
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method @NonNull public android.app.PendingIntent getIntent();
-    method public boolean getSuppressInitialNotification();
+    method @Deprecated public boolean getSuppressInitialNotification();
+    method public boolean getSuppressNotification();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
   }
@@ -5494,7 +5496,8 @@
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
-    method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
+    method @Deprecated @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressNotification(boolean);
   }
 
   public static class Notification.Builder {
@@ -9515,7 +9518,7 @@
     method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
     method public static boolean getSyncAutomatically(android.accounts.Account, String);
     method @Nullable public final String getType(@NonNull android.net.Uri);
-    method @NonNull public final android.content.ContentResolver.TypeInfo getTypeInfo(@NonNull String);
+    method @NonNull public final android.content.ContentResolver.MimeTypeInfo getTypeInfo(@NonNull String);
     method @Nullable public final android.net.Uri insert(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues);
     method public static boolean isSyncActive(android.accounts.Account, String);
     method public static boolean isSyncPending(android.accounts.Account, String);
@@ -9595,7 +9598,7 @@
     field public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1; // 0x1
   }
 
-  public static final class ContentResolver.TypeInfo {
+  public static final class ContentResolver.MimeTypeInfo {
     method @NonNull public CharSequence getContentDescription();
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method @NonNull public CharSequence getLabel();
@@ -10307,6 +10310,7 @@
     field public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
     field public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
     field public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+    field public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES";
     field public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
     field public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
     field public static final String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
@@ -23077,8 +23081,8 @@
     method @NonNull public android.media.AudioAttributes.Builder setAllowedCapturePolicy(int);
     method public android.media.AudioAttributes.Builder setContentType(int);
     method public android.media.AudioAttributes.Builder setFlags(int);
+    method @NonNull public android.media.AudioAttributes.Builder setHapticChannelsMuted(boolean);
     method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
-    method public android.media.AudioAttributes.Builder setMuteHapticChannels(boolean);
     method public android.media.AudioAttributes.Builder setUsage(int);
   }
 
@@ -38477,8 +38481,8 @@
 
   public final class MediaStore {
     ctor public MediaStore();
-    method @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
     method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
     method public static android.net.Uri getMediaScannerUri();
     method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @NonNull public static String getVersion(@NonNull android.content.Context);
@@ -38522,6 +38526,7 @@
     field public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
     field public static final String UNKNOWN_STRING = "<unknown>";
     field public static final String VOLUME_EXTERNAL = "external";
+    field public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
     field public static final String VOLUME_INTERNAL = "internal";
   }
 
@@ -38536,6 +38541,7 @@
     field public static final String ALBUM_ID = "album_id";
     field public static final String ALBUM_KEY = "album_key";
     field public static final String ARTIST = "artist";
+    field public static final String ARTIST_ID = "artist_id";
     field public static final String FIRST_YEAR = "minyear";
     field public static final String LAST_YEAR = "maxyear";
     field public static final String NUMBER_OF_SONGS = "numsongs";
@@ -38769,6 +38775,7 @@
     field public static final String RELATIVE_PATH = "relative_path";
     field public static final String SIZE = "_size";
     field public static final String TITLE = "title";
+    field public static final String VOLUME_NAME = "volume_name";
     field public static final String WIDTH = "width";
   }
 
@@ -44380,9 +44387,9 @@
     method public int getCid();
     method public int getLac();
     method @Deprecated public int getMcc();
-    method public String getMccString();
+    method @Nullable public String getMccString();
     method @Deprecated public int getMnc();
-    method public String getMncString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method @Deprecated public int getPsc();
     method public void writeToParcel(android.os.Parcel, int);
@@ -44394,9 +44401,9 @@
     method public int getCi();
     method public int getEarfcn();
     method @Deprecated public int getMcc();
-    method public String getMccString();
+    method @Nullable public String getMccString();
     method @Deprecated public int getMnc();
-    method public String getMncString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method public int getPci();
     method public int getTac();
@@ -44419,8 +44426,8 @@
     method public int getCid();
     method public int getCpid();
     method public int getLac();
-    method public String getMccString();
-    method public String getMncString();
+    method @Nullable public String getMccString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
@@ -44431,9 +44438,9 @@
     method public int getCid();
     method public int getLac();
     method @Deprecated public int getMcc();
-    method public String getMccString();
+    method @Nullable public String getMccString();
     method @Deprecated public int getMnc();
-    method public String getMncString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method public int getPsc();
     method public int getUarfcn();
@@ -44456,22 +44463,22 @@
   }
 
   public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable {
-    method public android.telephony.CellIdentityCdma getCellIdentity();
-    method public android.telephony.CellSignalStrengthCdma getCellSignalStrength();
+    method @NonNull public android.telephony.CellIdentityCdma getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoCdma> CREATOR;
   }
 
   public final class CellInfoGsm extends android.telephony.CellInfo implements android.os.Parcelable {
-    method public android.telephony.CellIdentityGsm getCellIdentity();
-    method public android.telephony.CellSignalStrengthGsm getCellSignalStrength();
+    method @NonNull public android.telephony.CellIdentityGsm getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrengthGsm getCellSignalStrength();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoGsm> CREATOR;
   }
 
   public final class CellInfoLte extends android.telephony.CellInfo implements android.os.Parcelable {
-    method public android.telephony.CellIdentityLte getCellIdentity();
-    method public android.telephony.CellSignalStrengthLte getCellSignalStrength();
+    method @NonNull public android.telephony.CellIdentityLte getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrengthLte getCellSignalStrength();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR;
   }
@@ -44507,7 +44514,7 @@
     method public abstract boolean equals(Object);
     method public abstract int getAsuLevel();
     method public abstract int getDbm();
-    method public abstract int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public abstract int getLevel();
     method public abstract int hashCode();
     field public static final int SIGNAL_STRENGTH_GOOD = 3; // 0x3
     field public static final int SIGNAL_STRENGTH_GREAT = 4; // 0x4
@@ -44527,7 +44534,7 @@
     method public int getEvdoEcio();
     method public int getEvdoLevel();
     method public int getEvdoSnr();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthCdma> CREATOR;
   }
@@ -44537,7 +44544,7 @@
     method public int getAsuLevel();
     method public int getBitErrorRate();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public int getTimingAdvance();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -44548,7 +44555,7 @@
     method public int getAsuLevel();
     method public int getCqi();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public int getRsrp();
     method public int getRsrq();
     method public int getRssi();
@@ -44565,7 +44572,7 @@
     method public int getCsiRsrq();
     method public int getCsiSinr();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public int getSsRsrp();
     method public int getSsRsrq();
     method public int getSsSinr();
@@ -44577,7 +44584,7 @@
     method public int describeContents();
     method public int getAsuLevel();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=0, to=4) public int getLevel();
     method public int getRscp();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthTdscdma> CREATOR;
@@ -44587,7 +44594,7 @@
     method public int describeContents();
     method public int getAsuLevel();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR;
   }
@@ -51671,7 +51678,7 @@
     method public void addOnGlobalLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
     method public void addOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
     method public void addOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
-    method public void addOnSystemGestureExclusionRectsChangedListener(java.util.function.Consumer<java.util.List<android.graphics.Rect>>);
+    method public void addOnSystemGestureExclusionRectsChangedListener(@NonNull java.util.function.Consumer<java.util.List<android.graphics.Rect>>);
     method public void addOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
     method public void addOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener);
     method public void addOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener);
@@ -51686,7 +51693,7 @@
     method public void removeOnGlobalLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
     method public void removeOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
     method public void removeOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
-    method public void removeOnSystemGestureExclusionRectsChangedListener(java.util.function.Consumer<java.util.List<android.graphics.Rect>>);
+    method public void removeOnSystemGestureExclusionRectsChangedListener(@NonNull java.util.function.Consumer<java.util.List<android.graphics.Rect>>);
     method public void removeOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
     method public void removeOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener);
     method public void removeOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener);
diff --git a/api/removed.txt b/api/removed.txt
index fe3e866..70ff50e 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -514,6 +514,7 @@
 
   public final class MediaStore {
     method @Deprecated @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
+    method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
     method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
     method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3ee6a49..c0da879 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -553,7 +553,7 @@
   }
 
   public class NotificationManager {
-    method @NonNull public java.util.List<java.lang.String> getAllowedAssistantCapabilities();
+    method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
     method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
     method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
     method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
@@ -1242,30 +1242,29 @@
 package android.bluetooth {
 
   public final class BluetoothAdapter {
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
     method public boolean disableBLE();
     method public boolean enableBLE();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isLeEnabled();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean registerMetadataListener(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothAdapter.MetadataListener, android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean unregisterMetadataListener(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
     field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
     field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
   }
 
-  public abstract static class BluetoothAdapter.MetadataListener {
-    ctor public BluetoothAdapter.MetadataListener();
-    method public void onMetadataChanged(android.bluetooth.BluetoothDevice, int, String);
+  public static interface BluetoothAdapter.OnMetadataChangedListener {
+    method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
   }
 
   public final class BluetoothDevice implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
     field public static final int ACCESS_ALLOWED = 1; // 0x1
@@ -1275,21 +1274,21 @@
     field public static final int METADATA_COMPANION_APP = 4; // 0x4
     field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
     field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
-    field public static final int METADATA_IS_UNTHETHERED_HEADSET = 6; // 0x6
+    field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6
     field public static final int METADATA_MAIN_ICON = 5; // 0x5
     field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
     field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
     field public static final int METADATA_MODEL_NAME = 1; // 0x1
     field public static final int METADATA_SOFTWARE_VERSION = 2; // 0x2
-    field public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12; // 0xc
-    field public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15; // 0xf
-    field public static final int METADATA_UNTHETHERED_CASE_ICON = 9; // 0x9
-    field public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10; // 0xa
-    field public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13; // 0xd
-    field public static final int METADATA_UNTHETHERED_LEFT_ICON = 7; // 0x7
-    field public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11; // 0xb
-    field public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14; // 0xe
-    field public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8; // 0x8
+    field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc
+    field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
+    field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
+    field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
+    field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
+    field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
+    field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
+    field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
+    field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
   }
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
@@ -5980,7 +5979,7 @@
     field public static final String NON_INDEXABLES_KEYS_PATH = "settings/non_indexables_key";
     field public static final String PROVIDER_INTERFACE = "android.content.action.SEARCH_INDEXABLES_PROVIDER";
     field public static final String SLICE_URI_PAIRS = "slice_uri_pairs";
-    field public static final String[] SLICE_URI_PAIRS_COLUMNS;
+    field @NonNull public static final String[] SLICE_URI_PAIRS_COLUMNS;
     field public static final String SLICE_URI_PAIRS_PATH = "settings/slice_uri_pairs";
   }
 
@@ -6028,7 +6027,7 @@
     method public android.database.Cursor query(android.net.Uri, String[], String, String[], String);
     method public abstract android.database.Cursor queryNonIndexableKeys(String[]);
     method public abstract android.database.Cursor queryRawData(String[]);
-    method public android.database.Cursor querySliceUriPairs();
+    method @Nullable public android.database.Cursor querySliceUriPairs();
     method public abstract android.database.Cursor queryXmlResources(String[]);
     method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
   }
@@ -6062,11 +6061,6 @@
     field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
     field public static final String CARRIER_APP_NAMES = "carrier_app_names";
     field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
-    field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
-    field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-    field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1
-    field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
-    field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
     field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
     field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
     field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
@@ -6636,8 +6630,8 @@
     method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
     method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
     method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
+    method public void onAllowedAdjustmentsChanged();
     method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
-    method public void onCapabilitiesChanged();
     method public void onNotificationDirectReplied(@NonNull String);
     method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
     method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
diff --git a/api/test-current.txt b/api/test-current.txt
index b35b90f..c3215a6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+    field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
     field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
@@ -328,8 +329,14 @@
   }
 
   public class NotificationManager {
+    method public void allowAssistantAdjustment(String);
+    method public void disallowAssistantAdjustment(String);
+    method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
+    method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
     method public android.content.ComponentName getEffectsSuppressor();
+    method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
     method public boolean matchesCallFilter(android.os.Bundle);
+    method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
   }
 
   public final class PictureInPictureParams implements android.os.Parcelable {
@@ -2160,11 +2167,6 @@
     field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls";
     field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
     field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
-    field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
-    field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-    field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1
-    field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
-    field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
     field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
     field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
     field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
@@ -2459,10 +2461,49 @@
 
 package android.service.notification {
 
+  public final class Adjustment implements android.os.Parcelable {
+    ctor public Adjustment(String, String, android.os.Bundle, CharSequence, int);
+    ctor public Adjustment(@NonNull String, @NonNull String, @NonNull android.os.Bundle, @NonNull CharSequence, @NonNull android.os.UserHandle);
+    method public int describeContents();
+    method @NonNull public CharSequence getExplanation();
+    method @NonNull public String getKey();
+    method @NonNull public String getPackage();
+    method @NonNull public android.os.Bundle getSignals();
+    method public int getUser();
+    method @NonNull public android.os.UserHandle getUserHandle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+    field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
+    field public static final String KEY_IMPORTANCE = "key_importance";
+    field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
+    field public static final String KEY_TEXT_REPLIES = "key_text_replies";
+    field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
+  }
+
   @Deprecated public abstract class ConditionProviderService extends android.app.Service {
     method @Deprecated public boolean isBound();
   }
 
+  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+    ctor public NotificationAssistantService();
+    method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
+    method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
+    method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
+    method public void onAllowedAdjustmentsChanged();
+    method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public void onNotificationDirectReplied(@NonNull String);
+    method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
+    method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
+    method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
+    method public abstract void onNotificationSnoozedUntilContext(@NonNull android.service.notification.StatusBarNotification, @NonNull String);
+    method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>);
+    method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
+    method public final void unsnoozeNotification(@NonNull String);
+    field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+    field public static final int SOURCE_FROM_APP = 0; // 0x0
+    field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     method public void onNotificationRemoved(@NonNull android.service.notification.StatusBarNotification, @NonNull android.service.notification.NotificationListenerService.RankingMap, @NonNull android.service.notification.NotificationStats, int);
   }
@@ -2658,6 +2699,7 @@
   public class TelephonyManager {
     method public int checkCarrierPrivilegesForPackage(String);
     method public int getCarrierIdListVersion();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
@@ -2840,31 +2882,6 @@
     method public void writeRawZigZag64(long);
   }
 
-  public final class ProtoInputStream extends android.util.proto.ProtoStream {
-    ctor public ProtoInputStream(java.io.InputStream, int);
-    ctor public ProtoInputStream(java.io.InputStream);
-    ctor public ProtoInputStream(byte[]);
-    method public int decodeZigZag32(int);
-    method public long decodeZigZag64(long);
-    method public String dumpDebugData();
-    method public void end(long);
-    method public int getFieldNumber();
-    method public int getOffset();
-    method public int getWireType();
-    method public boolean isNextField(long) throws java.io.IOException;
-    method public int nextField() throws java.io.IOException;
-    method public boolean readBoolean(long) throws java.io.IOException;
-    method public byte[] readBytes(long) throws java.io.IOException;
-    method public double readDouble(long) throws java.io.IOException;
-    method public float readFloat(long) throws java.io.IOException;
-    method public int readInt(long) throws java.io.IOException;
-    method public long readLong(long) throws java.io.IOException;
-    method public String readString(long) throws java.io.IOException;
-    method public void skip() throws java.io.IOException;
-    method public long start(long) throws java.io.IOException;
-    field public static final int NO_MORE_FIELDS = -1; // 0xffffffff
-  }
-
   public final class ProtoOutputStream extends android.util.proto.ProtoStream {
     ctor public ProtoOutputStream();
     ctor public ProtoOutputStream(int);
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 017cb6d..15d248f 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -235,6 +235,7 @@
         "tests/condition/CombinationConditionTracker_test.cpp",
         "tests/condition/SimpleConditionTracker_test.cpp",
         "tests/condition/StateTracker_test.cpp",
+        "tests/condition/ConditionTimer_test.cpp",
         "tests/metrics/OringDurationTracker_test.cpp",
         "tests/metrics/MaxDurationTracker_test.cpp",
         "tests/metrics/CountMetricProducer_test.cpp",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 146cf0c..90ba7ce 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -159,7 +159,7 @@
         BiometricAcquired biometric_acquired = 87;
         BiometricAuthenticated biometric_authenticated = 88;
         BiometricErrorOccurred biometric_error_occurred = 89;
-        Notification notification = 90;
+        // Atom number 90 is available for use.
         BatteryHealthSnapshot battery_health_snapshot = 91;
         SlowIo slow_io = 92;
         BatteryCausedShutdown battery_caused_shutdown = 93;
@@ -176,23 +176,38 @@
         FlagFlipUpdateOccurred flag_flip_update_occurred = 101;
         BinaryPushStateChanged binary_push_state_changed = 102;
         DevicePolicyEvent device_policy_event = 103;
-        DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104;
-        DocsUIFileOperationCopyMoveModeReported docs_ui_file_op_copy_move_mode_reported = 105;
-        DocsUIFileOperationFailureReported docs_ui_file_op_failure = 106;
-        DocsUIFileOperationReported docs_ui_provider_file_op = 107;
-        DocsUIInvalidScopedAccessRequestReported docs_ui_invalid_scoped_access_request = 108;
-        DocsUILaunchReported docs_ui_launch_reported = 109;
-        DocsUIRootVisitedReported docs_ui_root_visited = 110;
-        DocsUIStartupMsReported docs_ui_startup_ms = 111;
-        DocsUIUserActionReported docs_ui_user_action_reported = 112;
+        DocsUIFileOperationCanceledReported docs_ui_file_op_canceled =
+            104 [(log_from_module) = "docsui"];
+        DocsUIFileOperationCopyMoveModeReported
+            docs_ui_file_op_copy_move_mode_reported =
+            105 [(log_from_module) = "docsui"];
+        DocsUIFileOperationFailureReported docs_ui_file_op_failure =
+            106 [(log_from_module) = "docsui"];
+        DocsUIFileOperationReported docs_ui_provider_file_op =
+            107 [(log_from_module) = "docsui"];
+        DocsUIInvalidScopedAccessRequestReported
+            docs_ui_invalid_scoped_access_request =
+            108 [(log_from_module) = "docsui"];
+        DocsUILaunchReported docs_ui_launch_reported =
+            109 [(log_from_module) = "docsui"];
+        DocsUIRootVisitedReported docs_ui_root_visited =
+            110 [(log_from_module) = "docsui"];
+        DocsUIStartupMsReported docs_ui_startup_ms =
+            111 [(log_from_module) = "docsui"];
+        DocsUIUserActionReported docs_ui_user_action_reported =
+            112 [(log_from_module) = "docsui"];
         WifiEnabledStateChanged wifi_enabled_state_changed = 113;
         WifiRunningStateChanged wifi_running_state_changed = 114;
         AppCompacted app_compacted = 115;
         NetworkDnsEventReported network_dns_event_reported = 116 [(log_from_module) = "resolv"];
-        DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported = 117;
-        DocsUIPickResultReported docs_ui_pick_result_reported = 118;
-        DocsUISearchModeReported docs_ui_search_mode_reported = 119;
-        DocsUISearchTypeReported docs_ui_search_type_reported = 120;
+        DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported =
+            117 [(log_from_module) = "docsui"];
+        DocsUIPickResultReported docs_ui_pick_result_reported =
+            118 [(log_from_module) = "docsui"];
+        DocsUISearchModeReported docs_ui_search_mode_reported =
+            119 [(log_from_module) = "docsui"];
+        DocsUISearchTypeReported docs_ui_search_type_reported =
+            120 [(log_from_module) = "docsui"];
         DataStallEvent data_stall_event = 121;
         RescuePartyResetReported rescue_party_reset_reported = 122;
         SignedConfigReported signed_config_reported = 123;
@@ -3199,76 +3214,6 @@
     optional bool success = 4;
 }
 
-message Notification {
-
-    // Type of notification event.
-    enum Type {
-        TYPE_UNKNOWN = 0;
-        // Notification became visible to the user.
-        TYPE_OPEN = 1;
-        // Notification became hidden.
-        TYPE_CLOSE = 2;
-        // Notification switched to detail mode.
-        TYPE_DETAIL = 3;
-        // Notification was clicked.
-        TYPE_ACTION = 4;
-        // Notification was dismissed.
-        TYPE_DISMISS = 5;
-        // Notification switched to summary mode. The enum value of 14 is to
-        // match that of metrics_constants.
-        TYPE_COLLAPSE = 14;
-    }
-    optional Type type = 1;
-
-    // Package name associated with the notification.
-    optional string package_name = 2;
-
-    // Tag associated with notification.
-    optional string tag = 3;
-
-    // Application-supplied ID associated with the notification.
-    optional int32 id = 4;
-
-    // Index of notification in the notification panel.
-    optional int32 shade_index = 5;
-
-    // The number of notifications in the notification panel.
-    optional int32 shade_count = 6;
-
-    // Importance for the notification.
-    optional int32 importance = 7;
-
-    // ID for the notification channel.
-    optional string channel_id = 8;
-
-    // Importance for the notification channel.
-    optional int32 channel_importance = 9;
-
-    // Application-supplied ID associated with the notifications group.
-    optional string group_id = 10;
-
-    // Whether notification was a group summary.
-    optional bool group_summary = 11;
-
-    // Reason for dismissal of a notification. This field is only meaningful for
-    // TYPE_DISMISS events.
-    optional int32 dismiss_reason = 12;
-
-    // The first post time of notification, stable across updates.
-    optional int64 creation_millis = 13;
-
-    // The most recent interruption time, or the creation time if no updates.
-    // Differs from update_millis because updates are filtered based on whether
-    // they actually interrupted the user.
-    optional int64 interruption_millis = 14;
-
-    // The most recent update time, or the creation time if no updates.
-    optional int64 update_millis = 15;
-
-    // The most recent visibility event.
-    optional int64 visible_millis = 16;
-}
-
 /*
  * Logs when a flag flip update occurrs. Used for mainline modules that update via flag flips.
  */
@@ -3321,13 +3266,12 @@
         INSTALLER_ROLLBACK_BOOT_TRIGGERED_FAILURE = 14;
         INSTALLER_ROLLBACK_SUCCESS = 15;
         INSTALLER_ROLLBACK_FAILURE = 16;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_REMOVE_FROM_QUEUE = 17;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_INITIATED = 18;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_SUCCESS = 19;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_FAILURE = 20;
-        INSTALL_STAGED_CANCEL_REQUESTED = 21;
-        INSTALL_STAGED_CANCEL_SUCCESS = 22;
-        INSTALL_STAGED_CANCEL_FAILURE = 23;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_REQUESTED = 17;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_SUCCESS = 18;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_FAILURE = 19;
+        INSTALL_STAGED_CANCEL_REQUESTED = 20;
+        INSTALL_STAGED_CANCEL_SUCCESS = 21;
+        INSTALL_STAGED_CANCEL_FAILURE = 22;
     }
     optional State state = 6;
     // Possible experiment ids for monitoring this push.
@@ -4989,6 +4933,8 @@
     UNKNOWN = 0;
     SOME = 1;
     FULL = 2;
+    PERSISTENT = 3;
+    BFGS = 4;
   }
   optional Action action = 3;
 
@@ -5816,13 +5762,12 @@
         INSTALLER_ROLLBACK_BOOT_TRIGGERED_FAILURE = 14;
         INSTALLER_ROLLBACK_SUCCESS = 15;
         INSTALLER_ROLLBACK_FAILURE = 16;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_REMOVE_FROM_QUEUE = 17;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_INITIATED = 18;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_SUCCESS = 19;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_FAILURE = 20;
-        INSTALL_STAGED_CANCEL_REQUESTED = 21;
-        INSTALL_STAGED_CANCEL_SUCCESS = 22;
-        INSTALL_STAGED_CANCEL_FAILURE = 23;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_REQUESTED = 17;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_SUCCESS = 18;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_FAILURE = 19;
+        INSTALL_STAGED_CANCEL_REQUESTED = 20;
+        INSTALL_STAGED_CANCEL_SUCCESS = 21;
+        INSTALL_STAGED_CANCEL_FAILURE = 22;
     }
     optional Status status = 4;
 }
diff --git a/cmds/statsd/src/condition/ConditionTimer.h b/cmds/statsd/src/condition/ConditionTimer.h
new file mode 100644
index 0000000..442bc11
--- /dev/null
+++ b/cmds/statsd/src/condition/ConditionTimer.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <gtest/gtest_prod.h>
+#include <stdint.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * A simple stopwatch to time the duration of condition being true.
+ *
+ * The owner of the stopwatch (MetricProducer) is responsible to notify the stopwatch when condition
+ * changes (start/pause), and when to start a new bucket (a new lap basically). All timestamps
+ * should be elapsedRealTime in nano seconds.
+ *
+ * Keep the timer simple and inline everything. This class is *NOT* thread safe. Caller is
+ * responsible for thread safety.
+ */
+class ConditionTimer {
+public:
+    explicit ConditionTimer(bool initCondition, int64_t bucketStartNs) : mCondition(initCondition) {
+        if (initCondition) {
+            mLastConditionTrueTimestampNs = bucketStartNs;
+        }
+    };
+
+    // Tracks how long the condition has been stayed true in the *current* bucket.
+    // When a new bucket is created, this value will be reset to 0.
+    int64_t mTimerNs = 0;
+
+    // Last elapsed real timestamp when condition turned to true
+    // When a new bucket is created and the condition is true, then the timestamp is set
+    // to be the bucket start timestamp.
+    int64_t mLastConditionTrueTimestampNs = 0;
+
+    bool mCondition = false;
+
+    int64_t newBucketStart(int64_t nextBucketStartNs) {
+        if (mCondition) {
+            mTimerNs += (nextBucketStartNs - mLastConditionTrueTimestampNs);
+            mLastConditionTrueTimestampNs = nextBucketStartNs;
+        }
+
+        int64_t temp = mTimerNs;
+        mTimerNs = 0;
+        return temp;
+    }
+
+    void onConditionChanged(bool newCondition, int64_t timestampNs) {
+        if (newCondition == mCondition) {
+            return;
+        }
+        mCondition = newCondition;
+        if (newCondition) {
+            mLastConditionTrueTimestampNs = timestampNs;
+        } else {
+            mTimerNs += (timestampNs - mLastConditionTrueTimestampNs);
+        }
+    }
+
+    FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_False);
+    FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_True);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 13eee5d..d6411a7 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -276,7 +276,8 @@
 }
 
 bool StatsPullerManager::PullerForMatcherExists(int tagId) const {
-    return kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
+    // Vendor pulled atoms might be registered after we parse the config.
+    return isVendorPulledAtom(tagId) || kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
 }
 
 void StatsPullerManager::updateAlarmLocked() {
@@ -449,9 +450,8 @@
         const sp<IStatsPullerCallback>& callback) {
     AutoMutex _l(mLock);
     // Platform pullers cannot be changed.
-    if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
-        VLOG("RegisterPullerCallback: atom tag %d is less than min tag %d",
-                atomTag, StatsdStats::kMaxPlatformAtomTag);
+    if (!isVendorPulledAtom(atomTag)) {
+        VLOG("RegisterPullerCallback: atom tag %d is not vendor pulled", atomTag);
         return;
     }
     VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
@@ -462,7 +462,7 @@
 void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) {
     AutoMutex _l(mLock);
     // Platform pullers cannot be changed.
-    if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
+    if (!isVendorPulledAtom(atomTag)) {
         return;
     }
     StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 88ecccc..53f12ac 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -160,6 +160,12 @@
     // Max platform atom tag number.
     static const int32_t kMaxPlatformAtomTag = 100000;
 
+    // Vendor pulled atom start id.
+    static const int32_t kVendorPulledAtomStartTag = 150000;
+
+    // Max accepted atom id.
+    static const int32_t kMaxAtomTag = 200000;
+
     static const int64_t kInt64Max = 0x7fffffffffffffffLL;
 
     /**
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 18bfdfc..90a4e8b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -72,6 +72,7 @@
 const int FIELD_ID_BUCKET_NUM = 4;
 const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
 const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
+const int FIELD_ID_CONDITION_TRUE_NS = 10;
 
 const Value ZERO_LONG((int64_t)0);
 const Value ZERO_DOUBLE((int64_t)0);
@@ -107,7 +108,8 @@
       mCurrentBucketIsInvalid(false),
       mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
                                                       : StatsdStats::kPullMaxDelayNs),
-      mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()) {
+      mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
+      mConditionTimer(mCondition == ConditionState::kTrue, timeBaseNs) {
     int64_t bucketSizeMills = 0;
     if (metric.has_bucket()) {
         bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
@@ -153,6 +155,7 @@
     // flushIfNeeded to adjust start and end to bucket boundaries.
     // Adjust start for partial bucket
     mCurrentBucketStartTimeNs = startTimeNs;
+    mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
     // Kicks off the puller immediately if condition is true and diff based.
     if (mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
         pullAndMatchEventsLocked(startTimeNs, mCondition);
@@ -293,6 +296,11 @@
                 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
                                    (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
             }
+            // only write the condition timer value if the metric has a condition.
+            if (mConditionTrackerIndex >= 0) {
+                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_TRUE_NS,
+                                   (long long)bucket.mConditionTrueNs);
+            }
             for (int i = 0; i < (int)bucket.valueIndex.size(); i ++) {
                 int index = bucket.valueIndex[i];
                 const Value& value = bucket.values[i];
@@ -386,19 +394,19 @@
             resetBase();
         }
         mCondition = newCondition;
-
     } else {
         VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
              (long long)mCurrentBucketStartTimeNs);
         StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
         invalidateCurrentBucket();
-        // Something weird happened. If we received another event if the future, the condition might
+        // Something weird happened. If we received another event in the future, the condition might
         // be wrong.
         mCondition = initialCondition(mConditionTrackerIndex);
     }
 
     // This part should alway be called.
     flushIfNeededLocked(eventTimeNs);
+    mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
 }
 
 void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition) {
@@ -799,12 +807,14 @@
          (int)mCurrentSlicedBucket.size());
     int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
     int64_t bucketEndTime = eventTimeNs < fullBucketEndTimeNs ? eventTimeNs : fullBucketEndTimeNs;
-
+    // Close the current bucket.
+    int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime);
     bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
     if (isBucketLargeEnough && !mCurrentBucketIsInvalid) {
         // The current bucket is large enough to keep.
         for (const auto& slice : mCurrentSlicedBucket) {
             ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second);
+            bucket.mConditionTrueNs = conditionTrueDuration;
             // it will auto create new vector of ValuebucketInfo if the key is not found.
             if (bucket.valueIndex.size() > 0) {
                 auto& bucketList = mPastBuckets[slice.first];
@@ -817,6 +827,8 @@
 
     appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
     initCurrentSlicedBucket(nextBucketStartTimeNs);
+    // Update the condition timer again, in case we skipped buckets.
+    mConditionTimer.newBucketStart(nextBucketStartTimeNs);
     mCurrentBucketNum += numBucketsForward;
 }
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 12cec5d..0f56337 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -19,12 +19,13 @@
 #include <gtest/gtest_prod.h>
 #include <utils/threads.h>
 #include <list>
-#include "../anomaly/AnomalyTracker.h"
-#include "../condition/ConditionTracker.h"
-#include "../external/PullDataReceiver.h"
-#include "../external/StatsPullerManager.h"
-#include "../matchers/EventMatcherWizard.h"
-#include "../stats_log_util.h"
+#include "anomaly/AnomalyTracker.h"
+#include "condition/ConditionTimer.h"
+#include "condition/ConditionTracker.h"
+#include "external/PullDataReceiver.h"
+#include "external/StatsPullerManager.h"
+#include "matchers/EventMatcherWizard.h"
+#include "stats_log_util.h"
 #include "MetricProducer.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
@@ -37,6 +38,9 @@
     int64_t mBucketEndNs;
     std::vector<int> valueIndex;
     std::vector<Value> values;
+    // If the metric has no condition, then this field is just wasted.
+    // When we tune statsd memory usage in the future, this is a candidate to optimize.
+    int64_t mConditionTrueNs;
 };
 
 
@@ -228,6 +232,8 @@
 
     const bool mSplitBucketForAppUpgrade;
 
+    ConditionTimer mConditionTimer;
+
     FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
     FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange);
     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 1dfc433..54ca757 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -129,6 +129,8 @@
   optional int64 start_bucket_elapsed_millis = 5;
 
   optional int64 end_bucket_elapsed_millis = 6;
+
+  optional int64 condition_true_nanos = 10;
 }
 
 message ValueMetricData {
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index cdef874..2a18e22 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -96,6 +96,10 @@
     return atomId <= util::kMaxPushedAtomId && atomId > 1;
 }
 
+inline bool isVendorPulledAtom(int atomId) {
+    return atomId >= StatsdStats::kVendorPulledAtomStartTag && atomId < StatsdStats::kMaxAtomTag;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/tests/condition/ConditionTimer_test.cpp b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
new file mode 100644
index 0000000..ea02cd3
--- /dev/null
+++ b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
@@ -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.
+
+#include "src/condition/ConditionTimer.h"
+
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static int64_t time_base = 10;
+static int64_t ct_start_time = 200;
+
+TEST(ConditionTimerTest, TestTimer_Inital_False) {
+    ConditionTimer timer(false, time_base);
+    EXPECT_EQ(false, timer.mCondition);
+    EXPECT_EQ(0, timer.mTimerNs);
+
+    EXPECT_EQ(0, timer.newBucketStart(ct_start_time));
+    EXPECT_EQ(0, timer.mTimerNs);
+
+    timer.onConditionChanged(true, ct_start_time + 5);
+    EXPECT_EQ(ct_start_time + 5, timer.mLastConditionTrueTimestampNs);
+    EXPECT_EQ(true, timer.mCondition);
+
+    EXPECT_EQ(95, timer.newBucketStart(ct_start_time + 100));
+    EXPECT_EQ(ct_start_time + 100, timer.mLastConditionTrueTimestampNs);
+    EXPECT_EQ(true, timer.mCondition);
+}
+
+TEST(ConditionTimerTest, TestTimer_Inital_True) {
+    ConditionTimer timer(true, time_base);
+    EXPECT_EQ(true, timer.mCondition);
+    EXPECT_EQ(0, timer.mTimerNs);
+
+    EXPECT_EQ(ct_start_time - time_base, timer.newBucketStart(ct_start_time));
+    EXPECT_EQ(true, timer.mCondition);
+    EXPECT_EQ(0, timer.mTimerNs);
+    EXPECT_EQ(ct_start_time, timer.mLastConditionTrueTimestampNs);
+
+    timer.onConditionChanged(false, ct_start_time + 5);
+    EXPECT_EQ(5, timer.mTimerNs);
+
+    EXPECT_EQ(5, timer.newBucketStart(ct_start_time + 100));
+    EXPECT_EQ(0, timer.mTimerNs);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index afa05a9..c12a5900 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -55,8 +55,11 @@
 
 static void assertPastBucketValuesSingleKey(
         const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets,
-        const std::initializer_list<int>& expectedValuesList) {
+        const std::initializer_list<int>& expectedValuesList,
+        const std::initializer_list<int64_t>& expectedDurationNsList) {
     std::vector<int> expectedValues(expectedValuesList);
+    std::vector<int64_t> expectedDurationNs(expectedDurationNsList);
+    ASSERT_EQ(expectedValues.size(), expectedDurationNs.size());
     if (expectedValues.size() == 0) {
         ASSERT_EQ(0, mPastBuckets.size());
         return;
@@ -69,10 +72,11 @@
     for (int i = 0; i < expectedValues.size(); i++) {
         EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value)
                 << "Values differ at index " << i;
+        EXPECT_EQ(expectedDurationNs[i], buckets[i].mConditionTrueNs)
+                << "Condition duration value differ at index " << i;
     }
 }
 
-
 class ValueMetricProducerTestHelper {
 
  public:
@@ -237,6 +241,7 @@
     EXPECT_EQ(8, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -256,7 +261,9 @@
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
     EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
     EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -275,8 +282,11 @@
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
     EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
     EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
     EXPECT_EQ(13, valueProducer->mPastBuckets.begin()->second[2].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[2].mConditionTrueNs);
 }
 
 TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
@@ -326,8 +336,11 @@
     EXPECT_EQ(2UL, buckets.size());
     // Full bucket (2 - 1)
     EXPECT_EQ(1, buckets[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, buckets[0].mConditionTrueNs);
     // Full bucket (5 - 3)
     EXPECT_EQ(3, buckets[1].values[0].long_value);
+    // partial bucket [bucket2StartTimeNs, bucket2StartTimeNs + 2]
+    EXPECT_EQ(2, buckets[1].mConditionTrueNs);
 }
 
 /*
@@ -385,6 +398,7 @@
     EXPECT_EQ(8, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -402,6 +416,7 @@
     EXPECT_EQ(8, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -420,6 +435,7 @@
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
     EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
 }
 
 /*
@@ -468,6 +484,7 @@
     EXPECT_EQ(10, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -485,14 +502,16 @@
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
     EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
     EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
 }
 
 /*
  * Tests pulled atoms with no conditions and take zero value after reset
  */
 TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
     sp<ValueMetricProducer> valueProducer =
@@ -546,6 +565,7 @@
     EXPECT_EQ(26, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
     EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
 }
 
 /*
@@ -574,6 +594,15 @@
                 event->init();
                 data->push_back(event);
                 return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
+                event->write(tagId);
+                event->write(180);
+                event->init();
+                data->push_back(event);
+                return true;
             }));
 
     sp<ValueMetricProducer> valueProducer =
@@ -598,7 +627,7 @@
     event->init();
     allData.push_back(event);
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -609,7 +638,7 @@
     EXPECT_EQ(10, curInterval.value.long_value);
 
     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -617,6 +646,9 @@
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(20, curInterval.value.long_value);
     EXPECT_EQ(false, curInterval.hasBase);
+
+    valueProducer->onConditionChanged(true, bucket3StartTimeNs + 1);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20}, {bucketSizeNs - 8, 1});
 }
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
@@ -705,8 +737,7 @@
     valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
     EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(20L,
-              valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20}, {150});
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -719,10 +750,12 @@
     EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
     EXPECT_EQ(20L,
               valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20, 30},
+                                    {150, bucketSizeNs - 150});
 }
 
 TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_split_bucket_for_app_upgrade(false);
 
     UidMap uidMap;
@@ -791,8 +824,10 @@
     // Expect one full buckets already done and starting a partial bucket.
     EXPECT_EQ(bucket2StartTimeNs-50, valueProducer->mCurrentBucketStartTimeNs);
     EXPECT_EQ(1UL, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(20L, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+    EXPECT_EQ(bucketStartTimeNs,
+              valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20},
+                                    {(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)});
     EXPECT_FALSE(valueProducer->mCondition);
 }
 
@@ -835,7 +870,7 @@
     EXPECT_EQ(30, curInterval.value.long_value);
 
     valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30});
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs});
 }
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
@@ -872,7 +907,8 @@
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(20, curInterval.value.long_value);
 
@@ -900,7 +936,7 @@
     EXPECT_EQ(50, curInterval.value.long_value);
 
     valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50});
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20});
 }
 
 TEST(ValueMetricProducerTest, TestAnomalyDetection) {
@@ -1008,7 +1044,8 @@
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     // startUpdated:true sum:0 start:11
     EXPECT_EQ(true, curInterval.hasBase);
@@ -1031,7 +1068,7 @@
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(23, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
 
     // pull 3 come late.
     // The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -1050,7 +1087,7 @@
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
 }
 
 /*
@@ -1089,7 +1126,8 @@
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
@@ -1098,7 +1136,7 @@
     // pull on bucket boundary come late, condition change happens before it
     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
     EXPECT_EQ(false, curInterval.hasBase);
 
     // Now the alarm is delivered.
@@ -1107,7 +1145,7 @@
     allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(false, curInterval.hasValue);
@@ -1160,7 +1198,8 @@
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     // startUpdated:false sum:0 start:100
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
@@ -1169,7 +1208,7 @@
 
     // pull on bucket boundary come late, condition change happens before it
     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
@@ -1177,7 +1216,7 @@
 
     // condition changed to true again, before the pull alarm is delivered
     valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
     curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(130, curInterval.base.long_value);
@@ -1194,12 +1233,13 @@
     EXPECT_EQ(140, curInterval.base.long_value);
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(10, curInterval.value.long_value);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
 
     allData.clear();
     allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs, 160));
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
+                                    {bucketSizeNs - 8, bucketSizeNs - 24});
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
@@ -1230,7 +1270,8 @@
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(10, curInterval.value.long_value);
     EXPECT_EQ(true, curInterval.hasValue);
 
@@ -1242,7 +1283,7 @@
     EXPECT_EQ(10, curInterval.value.long_value);
 
     valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10});
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs});
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
@@ -1273,7 +1314,8 @@
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(10, curInterval.value.long_value);
     EXPECT_EQ(true, curInterval.hasValue);
 
@@ -1335,7 +1377,9 @@
     valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value - 12.5) < epsilon);
+
+    EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value -
+                         12.5) < epsilon);
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
@@ -1366,7 +1410,8 @@
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(10, curInterval.value.long_value);
     EXPECT_EQ(true, curInterval.hasValue);
 
@@ -1378,7 +1423,7 @@
     EXPECT_EQ(25, curInterval.value.long_value);
 
     valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25});
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs});
 }
 
 TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
@@ -1410,7 +1455,8 @@
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(10, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
@@ -1449,7 +1495,7 @@
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs});
 }
 
 TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
@@ -1546,11 +1592,13 @@
     EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
 
+    EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
     EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
     EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
     EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
     EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
 
+    EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[1].mConditionTrueNs);
     EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
     EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
 }
@@ -1625,8 +1673,10 @@
 
     EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
     auto iterator = valueProducer->mPastBuckets.begin();
+    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
     EXPECT_EQ(8, iterator->second[0].values[0].long_value);
     iterator++;
+    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
     EXPECT_EQ(4, iterator->second[0].values[0].long_value);
 }
 
@@ -1795,7 +1845,7 @@
     EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
     EXPECT_FALSE(interval1.seenNewData);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
 
     auto it = valueProducer->mCurrentSlicedBucket.begin();
     for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
@@ -1810,7 +1860,7 @@
     EXPECT_EQ(4, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_FALSE(interval2.seenNewData);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
 
     // next pull somehow did not happen, skip to end of bucket 3
     allData.clear();
@@ -1828,7 +1878,7 @@
     EXPECT_EQ(5, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_FALSE(interval2.seenNewData);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
 
     allData.clear();
     event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -1846,8 +1896,10 @@
     ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
     auto iterator = valueProducer->mPastBuckets.begin();
     EXPECT_EQ(9, iterator->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
     iterator++;
     EXPECT_EQ(8, iterator->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
 }
 
 TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
@@ -1932,6 +1984,15 @@
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(50);
+                event->init();
+                data->push_back(event);
+                return false;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
                 event->write(tagId);
                 event->write(100);
@@ -1943,10 +2004,11 @@
     sp<ValueMetricProducer> valueProducer =
             ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer->mCondition = ConditionState::kTrue;
+    // Don't directly set mCondition; the real code never does that. Go through regular code path
+    // to avoid unexpected behaviors.
+    // valueProducer->mCondition = ConditionState::kTrue;
+    valueProducer->onConditionChanged(true, bucketStartTimeNs);
 
-    vector<shared_ptr<LogEvent>> allData;
-    valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
     EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
 
     valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
@@ -2406,7 +2468,7 @@
     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 
     EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
-    EXPECT_EQ(1, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1}, {bucketSizeNs - 12 + 1});
 }
 
 TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
@@ -2539,13 +2601,15 @@
             // Second onConditionChanged.
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 10, 5));
+                data->push_back(
+                        ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 10, 5));
                 return true;
             }))
             // Third onConditionChanged.
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                data->push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 10, 7));
+                data->push_back(
+                        ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 10, 7));
                 return true;
             }));
 
@@ -2572,7 +2636,7 @@
     valueProducer->onConditionChanged(false, bucket3StartTimeNs + 10);
 
     // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {bucketSizeNs - 10});
 }
 
 TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff) {
@@ -2592,7 +2656,7 @@
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs});
 }
 
 TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff) {
@@ -2619,7 +2683,7 @@
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19}, {bucketSizeNs});
 }
 
 TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade) {
@@ -2636,7 +2700,8 @@
             // notifyAppUpgrade.
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 2, 10));
+                data->push_back(
+                        ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 2, 10));
                 return true;
             }));
 
@@ -2646,7 +2711,7 @@
     valueProducer->notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
 
     // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9}, {bucketSizeNs});
 }
 
 TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
@@ -2678,6 +2743,12 @@
     auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(2, curInterval.value.long_value);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 1, 10));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 1);
+
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {2});
 }
 
 TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
@@ -2724,7 +2795,7 @@
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     // There was not global base available so all buckets are invalid.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {});
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {});
 }
 
 static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
@@ -2890,6 +2961,7 @@
     EXPECT_EQ(1, report.value_metrics().data_size());
     EXPECT_EQ(1, report.value_metrics().data(0).bucket_info_size());
     EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
+    EXPECT_EQ(10, report.value_metrics().data(0).bucket_info(0).condition_true_nanos());
 }
 
 
diff --git a/config/preloaded-classes b/config/preloaded-classes
index abdbab2..5910c28 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -756,7 +756,6 @@
 android.content.AsyncQueryHandler$WorkerArgs
 android.content.AsyncQueryHandler$WorkerHandler
 android.content.AsyncQueryHandler
-android.content.AsyncTaskLoader$LoadTask
 android.content.AsyncTaskLoader
 android.content.BroadcastReceiver$PendingResult$1
 android.content.BroadcastReceiver$PendingResult
@@ -3186,7 +3185,6 @@
 android.speech.tts.ITextToSpeechService$Stub$Proxy
 android.speech.tts.ITextToSpeechService
 android.speech.tts.TextToSpeech$Action
-android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
 android.speech.tts.TextToSpeech$Connection
 android.speech.tts.TextToSpeech$OnInitListener
 android.speech.tts.TextToSpeech
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist
index 59f605d..cd5a120 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-blacklist
@@ -1,6 +1,8 @@
+android.content.AsyncTaskLoader$LoadTask
 android.net.ConnectivityThread$Singleton
 android.os.AsyncTask
 android.os.FileObserver
+android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
 android.widget.Magnifier
 sun.nio.fs.UnixChannelFactory
 com.android.server.SystemConfig$PermissionEntry
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 2637764..c822d20 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -93,6 +93,12 @@
     public Account(Parcel in) {
         this.name = in.readString();
         this.type = in.readString();
+        if (TextUtils.isEmpty(name)) {
+            throw new android.os.BadParcelableException("the name must not be empty: " + name);
+        }
+        if (TextUtils.isEmpty(type)) {
+            throw new android.os.BadParcelableException("the type must not be empty: " + type);
+        }
         this.accessId = in.readString();
         if (accessId != null) {
             synchronized (sAccessedAccounts) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 883bcb8..9079ace 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -132,6 +132,7 @@
 import android.widget.Toast;
 import android.widget.Toolbar;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
@@ -820,8 +821,6 @@
     /** {@code true} if the activity lifecycle is in a state which supports picture-in-picture.
      * This only affects the client-side exception, the actual state check still happens in AMS. */
     private boolean mCanEnterPictureInPicture = false;
-    /** true if the activity is going through a transient pause */
-    /*package*/ boolean mTemporaryPause = false;
     /** true if the activity is being destroyed in order to recreate it with a new configuration */
     /*package*/ boolean mChangingConfigurations = false;
     @UnsupportedAppUsage
@@ -4906,6 +4905,17 @@
             mTaskDescription.setNavigationBarColor(navigationBarColor);
         }
 
+        final int targetSdk = getApplicationInfo().targetSdkVersion;
+        final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q;
+        if (!targetPreQ) {
+            mTaskDescription.setEnsureStatusBarContrastWhenTransparent(a.getBoolean(
+                    R.styleable.ActivityTaskDescription_ensureStatusBarContrastWhenTransparent,
+                    false));
+            mTaskDescription.setEnsureNavigationBarContrastWhenTransparent(a.getBoolean(
+                    R.styleable.ActivityTaskDescription_ensureNavigationBarContrastWhenTransparent,
+                    true));
+        }
+
         a.recycle();
         setTaskDescription(mTaskDescription);
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 395c867..4f388a4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -986,6 +986,8 @@
         private int mColorBackground;
         private int mStatusBarColor;
         private int mNavigationBarColor;
+        private boolean mEnsureStatusBarContrastWhenTransparent;
+        private boolean mEnsureNavigationBarContrastWhenTransparent;
 
         /**
          * Creates the TaskDescription to the specified values.
@@ -998,7 +1000,7 @@
          */
         @Deprecated
         public TaskDescription(String label, Bitmap icon, int colorPrimary) {
-            this(label, icon, 0, null, colorPrimary, 0, 0, 0);
+            this(label, icon, 0, null, colorPrimary, 0, 0, 0, false, false);
             if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
                 throw new RuntimeException("A TaskDescription's primary color should be opaque");
             }
@@ -1014,7 +1016,7 @@
          *                     opaque.
          */
         public TaskDescription(String label, @DrawableRes int iconRes, int colorPrimary) {
-            this(label, null, iconRes, null, colorPrimary, 0, 0, 0);
+            this(label, null, iconRes, null, colorPrimary, 0, 0, 0, false, false);
             if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
                 throw new RuntimeException("A TaskDescription's primary color should be opaque");
             }
@@ -1029,7 +1031,7 @@
          */
         @Deprecated
         public TaskDescription(String label, Bitmap icon) {
-            this(label, icon, 0, null, 0, 0, 0, 0);
+            this(label, icon, 0, null, 0, 0, 0, 0, false, false);
         }
 
         /**
@@ -1040,7 +1042,7 @@
          *                activity.
          */
         public TaskDescription(String label, @DrawableRes int iconRes) {
-            this(label, null, iconRes, null, 0, 0, 0, 0);
+            this(label, null, iconRes, null, 0, 0, 0, 0, false, false);
         }
 
         /**
@@ -1049,19 +1051,21 @@
          * @param label A label and description of the current state of this activity.
          */
         public TaskDescription(String label) {
-            this(label, null, 0, null, 0, 0, 0, 0);
+            this(label, null, 0, null, 0, 0, 0, 0, false, false);
         }
 
         /**
          * Creates an empty TaskDescription.
          */
         public TaskDescription() {
-            this(null, null, 0, null, 0, 0, 0, 0);
+            this(null, null, 0, null, 0, 0, 0, 0, false, false);
         }
 
         /** @hide */
         public TaskDescription(String label, Bitmap bitmap, int iconRes, String iconFilename,
-                int colorPrimary, int colorBackground, int statusBarColor, int navigationBarColor) {
+                int colorPrimary, int colorBackground, int statusBarColor, int navigationBarColor,
+                boolean ensureStatusBarContrastWhenTransparent,
+                boolean ensureNavigationBarContrastWhenTransparent) {
             mLabel = label;
             mIcon = bitmap;
             mIconRes = iconRes;
@@ -1070,6 +1074,9 @@
             mColorBackground = colorBackground;
             mStatusBarColor = statusBarColor;
             mNavigationBarColor = navigationBarColor;
+            mEnsureStatusBarContrastWhenTransparent = ensureStatusBarContrastWhenTransparent;
+            mEnsureNavigationBarContrastWhenTransparent =
+                    ensureNavigationBarContrastWhenTransparent;
         }
 
         /**
@@ -1092,6 +1099,9 @@
             mColorBackground = other.mColorBackground;
             mStatusBarColor = other.mStatusBarColor;
             mNavigationBarColor = other.mNavigationBarColor;
+            mEnsureStatusBarContrastWhenTransparent = other.mEnsureStatusBarContrastWhenTransparent;
+            mEnsureNavigationBarContrastWhenTransparent =
+                    other.mEnsureNavigationBarContrastWhenTransparent;
         }
 
         /**
@@ -1114,6 +1124,9 @@
             if (other.mNavigationBarColor != 0) {
                 mNavigationBarColor = other.mNavigationBarColor;
             }
+            mEnsureStatusBarContrastWhenTransparent = other.mEnsureStatusBarContrastWhenTransparent;
+            mEnsureNavigationBarContrastWhenTransparent =
+                    other.mEnsureNavigationBarContrastWhenTransparent;
         }
 
         private TaskDescription(Parcel source) {
@@ -1272,6 +1285,37 @@
             return mNavigationBarColor;
         }
 
+        /**
+         * @hide
+         */
+        public boolean getEnsureStatusBarContrastWhenTransparent() {
+            return mEnsureStatusBarContrastWhenTransparent;
+        }
+
+        /**
+         * @hide
+         */
+        public void setEnsureStatusBarContrastWhenTransparent(
+                boolean ensureStatusBarContrastWhenTransparent) {
+            mEnsureStatusBarContrastWhenTransparent = ensureStatusBarContrastWhenTransparent;
+        }
+
+        /**
+         * @hide
+         */
+        public boolean getEnsureNavigationBarContrastWhenTransparent() {
+            return mEnsureNavigationBarContrastWhenTransparent;
+        }
+
+        /**
+         * @hide
+         */
+        public void setEnsureNavigationBarContrastWhenTransparent(
+                boolean ensureNavigationBarContrastWhenTransparent) {
+            mEnsureNavigationBarContrastWhenTransparent =
+                    ensureNavigationBarContrastWhenTransparent;
+        }
+
         /** @hide */
         public void saveToXml(XmlSerializer out) throws IOException {
             if (mLabel != null) {
@@ -1332,6 +1376,8 @@
             dest.writeInt(mColorBackground);
             dest.writeInt(mStatusBarColor);
             dest.writeInt(mNavigationBarColor);
+            dest.writeBoolean(mEnsureStatusBarContrastWhenTransparent);
+            dest.writeBoolean(mEnsureNavigationBarContrastWhenTransparent);
             if (mIconFilename == null) {
                 dest.writeInt(0);
             } else {
@@ -1348,6 +1394,8 @@
             mColorBackground = source.readInt();
             mStatusBarColor = source.readInt();
             mNavigationBarColor = source.readInt();
+            mEnsureStatusBarContrastWhenTransparent = source.readBoolean();
+            mEnsureNavigationBarContrastWhenTransparent = source.readBoolean();
             mIconFilename = source.readInt() > 0 ? source.readString() : null;
         }
 
@@ -1366,8 +1414,11 @@
             return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
                     " IconRes: " + mIconRes + " IconFilename: " + mIconFilename +
                     " colorPrimary: " + mColorPrimary + " colorBackground: " + mColorBackground +
-                    " statusBarColor: " + mColorBackground +
-                    " navigationBarColor: " + mNavigationBarColor;
+                    " statusBarColor: " + mStatusBarColor + (
+                    mEnsureStatusBarContrastWhenTransparent ? " (contrast when transparent)"
+                            : "") + " navigationBarColor: " + mNavigationBarColor + (
+                    mEnsureNavigationBarContrastWhenTransparent
+                            ? " (contrast when transparent)" : "");
         }
     }
 
@@ -2001,7 +2052,10 @@
     @RequiresPermission(android.Manifest.permission.REORDER_TASKS)
     public void moveTaskToFront(int taskId, @MoveTaskFlags int flags, Bundle options) {
         try {
-            getTaskService().moveTaskToFront(taskId, flags, options);
+            ActivityThread thread = ActivityThread.currentActivityThread();
+            IApplicationThread appThread = thread.getApplicationThread();
+            String packageName = mContext.getPackageName();
+            getTaskService().moveTaskToFront(appThread, packageName, taskId, flags, options);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4212,7 +4266,10 @@
          */
         public void moveToFront() {
             try {
-                mAppTaskImpl.moveToFront();
+                ActivityThread thread = ActivityThread.currentActivityThread();
+                IApplicationThread appThread = thread.getApplicationThread();
+                String packageName = ActivityThread.currentPackageName();
+                mAppTaskImpl.moveToFront(appThread, packageName);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index da9ea83..926044b 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -33,7 +33,6 @@
 import android.graphics.Bitmap.Config;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
@@ -925,8 +924,7 @@
                 // Unpackage the GraphicBuffer from the parceled thumbnail
                 final GraphicBuffer buffer = opts.getParcelable(KEY_ANIM_THUMBNAIL);
                 if (buffer != null) {
-                    mThumbnail = Bitmap.wrapHardwareBuffer(
-                            HardwareBuffer.createFromGraphicBuffer(buffer), null);
+                    mThumbnail = Bitmap.wrapHardwareBuffer(buffer, null);
                 }
                 mStartX = opts.getInt(KEY_ANIM_START_X, 0);
                 mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 38006dc..b37d117 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -615,7 +615,6 @@
                 sb.append(", finished=").append(activity.isFinishing());
                 sb.append(", destroyed=").append(activity.isDestroyed());
                 sb.append(", startedActivity=").append(activity.mStartedActivity);
-                sb.append(", temporaryPause=").append(activity.mTemporaryPause);
                 sb.append(", changingConfigurations=").append(activity.mChangingConfigurations);
                 sb.append("}");
             }
@@ -3319,35 +3318,15 @@
         }
     }
 
-    @UnsupportedAppUsage
-    void performNewIntents(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
+    @Override
+    public void handleNewIntent(IBinder token, List<ReferrerIntent> intents) {
         final ActivityClientRecord r = mActivities.get(token);
         if (r == null) {
             return;
         }
 
-        final boolean resumed = !r.paused;
-        if (resumed) {
-            r.activity.mTemporaryPause = true;
-            performPauseActivityIfNeeded(r, "performNewIntents");
-        }
         checkAndBlockForNetworkAccess();
         deliverNewIntents(r, intents);
-        if (resumed) {
-            performResumeActivity(token, false, "performNewIntents");
-            r.activity.mTemporaryPause = false;
-        } else if (andPause) {
-            // In this case the activity was in the paused state when we delivered the intent,
-            // to guarantee onResume gets called after onNewIntent we temporarily resume the
-            // activity and pause again as the caller wanted.
-            performResumeActivity(token, false, "performNewIntents");
-            performPauseActivityIfNeeded(r, "performNewIntents");
-        }
-    }
-
-    @Override
-    public void handleNewIntent(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
-        performNewIntents(token, intents, andPause);
     }
 
     public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
@@ -4662,7 +4641,6 @@
                 try {
                     // Now we are idle.
                     r.activity.mCalled = false;
-                    r.activity.mTemporaryPause = true;
                     mInstrumentation.callActivityOnPause(r.activity);
                     if (!r.activity.mCalled) {
                         throw new SuperNotCalledException(
@@ -4684,7 +4662,6 @@
             deliverResults(r, results, reason);
             if (resumed) {
                 r.activity.performResume(false, reason);
-                r.activity.mTemporaryPause = false;
             }
         }
     }
diff --git a/core/java/android/app/AppComponentFactory.java b/core/java/android/app/AppComponentFactory.java
index 2cec7f0..5b02817 100644
--- a/core/java/android/app/AppComponentFactory.java
+++ b/core/java/android/app/AppComponentFactory.java
@@ -35,11 +35,22 @@
 public class AppComponentFactory {
 
     /**
-     * Allows application to override the creation of the default class loader.
-     * This can be used to perform things such as dependency injection or setting up
-     * a custom class loader hierarchy.
+     * Selects the class loader which will be used by the platform to instantiate app components.
+     * <p>
+     * The default implementation of this method returns the {@code cl} parameter unchanged.
+     * Applications can override this method to set up a custom class loader or a custom class
+     * loader hierarchy and return it to the platform.
+     * <p>
+     * The method is a hook invoked before any application components are instantiated or the
+     * application Context is initialized. It is intended to allow the application's classes to
+     * be loaded from a different source than the base/split APK(s).
+     * <p>
+     * The default class loader {@code cl} is created by the platform and used to load the
+     * application's base or split APK(s). Its parent is typically the boot class loader, unless
+     * running under instrumentation. Its classname is configurable using the
+     * {@link android.R.attr#classLoader} manifest attribute.
      *
-     * @param cl        The default classloader instantiated by platform.
+     * @param cl        The default class loader created by the platform.
      * @param aInfo     Information about the application being loaded.
      */
     public @NonNull ClassLoader instantiateClassLoader(@NonNull ClassLoader cl,
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 70badfa..9dc8b45 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -150,8 +150,7 @@
             Configuration overrideConfig);
 
     /** Deliver new intent. */
-    public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents,
-            boolean andPause);
+    public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents);
 
     /** Deliver picture-in-picture mode change notification. */
     public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 65f1080..1785d2a 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -130,7 +130,8 @@
     List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType,
             int ignoreWindowingMode);
     @UnsupportedAppUsage
-    void moveTaskToFront(int task, int flags, in Bundle options);
+    void moveTaskToFront(in IApplicationThread caller, in String callingPackage, int task,
+            int flags, in Bundle options);
     @UnsupportedAppUsage
     int getTaskForActivity(in IBinder token, in boolean onlyRoot);
     ContentProviderHolder getContentProvider(in IApplicationThread caller, in String callingPackage,
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index a6b76cb..7953d42 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -149,7 +149,8 @@
     boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
     boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
             in Intent resultData);
-    void moveTaskToFront(int task, int flags, in Bundle options);
+    void moveTaskToFront(in IApplicationThread app, in String callingPackage, int task,
+            int flags, in Bundle options);
     int getTaskForActivity(in IBinder token, in boolean onlyRoot);
     void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
     ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
diff --git a/core/java/android/app/IAppTask.aidl b/core/java/android/app/IAppTask.aidl
index 61f6264..3ce7190 100644
--- a/core/java/android/app/IAppTask.aidl
+++ b/core/java/android/app/IAppTask.aidl
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.app.ActivityManager;
+import android.app.IApplicationThread;
 import android.content.Intent;
 import android.os.Bundle;
 
@@ -25,7 +26,7 @@
     void finishAndRemoveTask();
     @UnsupportedAppUsage
     ActivityManager.RecentTaskInfo getTaskInfo();
-    void moveToFront();
+    void moveToFront(in IApplicationThread appThread, in String callingPackage);
     int startActivity(IBinder whoThread, String callingPackage,
             in Intent intent, String resolvedType, in Bundle options);
     void setExcludeFromRecents(boolean exclude);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 7884872..b3c2429 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -70,9 +70,9 @@
     boolean areNotificationsEnabled(String pkg);
     int getPackageImportance(String pkg);
 
-    List<String> getAllowedAssistantCapabilities(String pkg);
-    void allowAssistantCapability(String adjustmentType);
-    void disallowAssistantCapability(String adjustmentType);
+    List<String> getAllowedAssistantAdjustments(String pkg);
+    void allowAssistantAdjustment(String adjustmentType);
+    void disallowAssistantAdjustment(String adjustmentType);
 
     boolean shouldHideSilentStatusIcons(String callingPkg);
     void setHideSilentStatusIcons(boolean hide);
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index a52fb1a..94b1d77 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -339,7 +339,7 @@
                     ArrayList<ReferrerIntent> intents = new ArrayList<>(1);
                     intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
                     if (localLOGV) Log.v(TAG, r.id + ": new intent");
-                    mActivityThread.performNewIntents(r, intents, false /* andPause */);
+                    mActivityThread.handleNewIntent(r, intents);
                     r.intent = intent;
                     moveToState(r, mCurState);
                     if (mSingleMode) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0ab1a85..5248329 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -618,9 +618,11 @@
     public static final int FLAG_CAN_COLORIZE = 0x00000800;
 
     /**
-     * Bit to be bitswised-ored into the {@link #flags} field that should be
-     * set if this notification can be shown as a bubble.
-     * @hide
+     * Bit to be bitswised-ored into the {@link #flags} field that should be set if this
+     * notification is showing as a bubble. This will be set by the system if it is determined
+     * that your notification is allowed to be a bubble.
+     *
+     * @see {@link Notification.Builder#setBubbleMetadata(BubbleMetadata)}
      */
     public static final int FLAG_BUBBLE = 0x00001000;
 
@@ -3578,9 +3580,9 @@
          * <p>This data will be ignored unless the notification is posted to a channel that
          * allows {@link NotificationChannel#canBubble() bubbles}.</p>
          *
-         * <b>Notifications with a valid and allowed bubble metadata will display in collapsed state
-         * outside of the notification shade on unlocked devices. When a user interacts with the
-         * collapsed state, the bubble intent will be invoked and displayed.</b>
+         * <p>Notifications allowed to bubble that have valid bubble metadata will display in
+         * collapsed state outside of the notification shade on unlocked devices. When a user
+         * interacts with the collapsed state, the bubble intent will be invoked and displayed.</p>
          */
         @NonNull
         public Builder setBubbleMetadata(@Nullable BubbleMetadata data) {
@@ -8555,16 +8557,16 @@
         private static final int FLAG_AUTO_EXPAND_BUBBLE = 0x00000001;
 
         /**
-         * If set and the app creating the bubble is in the foreground, the bubble will be posted
-         * <b>without</b> the associated notification in the notification shade. Subsequent update
-         * notifications to this bubble will post a notification in the shade.
+         * If set and the app posting the bubble is in the foreground, the bubble will
+         * be posted <b>without</b> the associated notification in the notification shade.
          *
-         * <p>If the app creating the bubble is not in the foreground this flag has no effect.</p>
+         * <p>If the app posting the bubble is not in the foreground this flag has no effect.</p>
          *
          * <p>Generally this flag should only be set if the user has performed an action to request
-         * or create a bubble.</p>
+         * or create a bubble, or if the user has seen the content in the notification and the
+         * notification is no longer relevant.</p>
          */
-        private static final int FLAG_SUPPRESS_INITIAL_NOTIFICATION = 0x00000002;
+        private static final int FLAG_SUPPRESS_NOTIFICATION = 0x00000002;
 
         private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
                 Icon icon, int height, @DimenRes int heightResId) {
@@ -8643,9 +8645,20 @@
          * @return whether this bubble should suppress the initial notification when it is posted.
          *
          * @see BubbleMetadata.Builder#setSuppressInitialNotification(boolean)
+         * @deprecated TO BE REMOVED, use {@link #getSuppressNotification()} instead.
          */
+        @Deprecated
         public boolean getSuppressInitialNotification() {
-            return (mFlags & FLAG_SUPPRESS_INITIAL_NOTIFICATION) != 0;
+            return (mFlags & FLAG_SUPPRESS_NOTIFICATION) != 0;
+        }
+
+        /**
+         * @return whether this bubble should suppress the notification when it is posted.
+         *
+         * @see BubbleMetadata.Builder#setSuppressInitialNotification(boolean)
+         */
+        public boolean getSuppressNotification() {
+            return (mFlags & FLAG_SUPPRESS_NOTIFICATION) != 0;
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<BubbleMetadata> CREATOR =
@@ -8804,11 +8817,31 @@
              *
              * <p>Generally this flag should only be set if the user has performed an action to
              * request or create a bubble.</p>
+             *
+             * @deprecated TO BE REMOVED, use {@link #setSuppressNotification(boolean)} instead.
              */
+            @Deprecated
             @NonNull
             public BubbleMetadata.Builder setSuppressInitialNotification(
                     boolean shouldSupressNotif) {
-                setFlag(FLAG_SUPPRESS_INITIAL_NOTIFICATION, shouldSupressNotif);
+                setFlag(FLAG_SUPPRESS_NOTIFICATION, shouldSupressNotif);
+                return this;
+            }
+
+            /**
+             * If set and the app posting the bubble is in the foreground, the bubble will be
+             * posted <b>without</b> the associated notification in the notification shade.
+             *
+             * <p>If the app posting the bubble is not in the foreground this flag has no effect.
+             * </p>
+             *
+             * <p>Generally this flag should only be set if the user has performed an action to
+             * request or create a bubble, or if the user has seen the content in the notification
+             * and the notification is no longer relevant.</p>
+             */
+            @NonNull
+            public BubbleMetadata.Builder setSuppressNotification(boolean shouldSupressNotif) {
+                setFlag(FLAG_SUPPRESS_NOTIFICATION, shouldSupressNotif);
                 return this;
             }
 
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 0bec21f..dd39376 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1169,6 +1169,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public boolean isNotificationAssistantAccessGranted(@NonNull ComponentName assistant) {
         INotificationManager service = getService();
         try {
@@ -1204,10 +1205,37 @@
      * @hide
      */
     @SystemApi
-    public @NonNull @Adjustment.Keys List<String> getAllowedAssistantCapabilities() {
+    @TestApi
+    public @NonNull @Adjustment.Keys List<String> getAllowedAssistantAdjustments() {
         INotificationManager service = getService();
         try {
-            return service.getAllowedAssistantCapabilities(mContext.getOpPackageName());
+            return service.getAllowedAssistantAdjustments(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public void allowAssistantAdjustment(String capability) {
+        INotificationManager service = getService();
+        try {
+            service.allowAssistantAdjustment(capability);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public void disallowAssistantAdjustment(String capability) {
+        INotificationManager service = getService();
+        try {
+            service.disallowAssistantAdjustment(capability);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1310,6 +1338,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant,
             boolean granted) {
         INotificationManager service = getService();
@@ -1332,6 +1361,7 @@
 
     /** @hide */
     @SystemApi
+    @TestApi
     public @Nullable ComponentName getAllowedNotificationAssistant() {
         INotificationManager service = getService();
         try {
diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java
index 4c7f56d..2d18838 100644
--- a/core/java/android/app/servertransaction/NewIntentItem.java
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -16,6 +16,8 @@
 
 package android.app.servertransaction;
 
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
+
 import android.annotation.UnsupportedAppUsage;
 import android.app.ClientTransactionHandler;
 import android.os.IBinder;
@@ -36,19 +38,17 @@
 
     @UnsupportedAppUsage
     private List<ReferrerIntent> mIntents;
-    private boolean mPause;
 
-    // TODO(lifecycler): Switch new intent handling to this scheme.
-    /*@Override
+    @Override
     public int getPostExecutionState() {
         return ON_RESUME;
-    }*/
+    }
 
     @Override
     public void execute(ClientTransactionHandler client, IBinder token,
             PendingTransactionActions pendingActions) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
-        client.handleNewIntent(token, mIntents, mPause);
+        client.handleNewIntent(token, mIntents);
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
@@ -58,13 +58,12 @@
     private NewIntentItem() {}
 
     /** Obtain an instance initialized with provided params. */
-    public static NewIntentItem obtain(List<ReferrerIntent> intents, boolean pause) {
+    public static NewIntentItem obtain(List<ReferrerIntent> intents) {
         NewIntentItem instance = ObjectPool.obtain(NewIntentItem.class);
         if (instance == null) {
             instance = new NewIntentItem();
         }
         instance.mIntents = intents;
-        instance.mPause = pause;
 
         return instance;
     }
@@ -72,7 +71,6 @@
     @Override
     public void recycle() {
         mIntents = null;
-        mPause = false;
         ObjectPool.recycle(this);
     }
 
@@ -82,13 +80,11 @@
     /** Write to Parcel. */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeBoolean(mPause);
         dest.writeTypedList(mIntents, flags);
     }
 
     /** Read from Parcel. */
     private NewIntentItem(Parcel in) {
-        mPause = in.readBoolean();
         mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
     }
 
@@ -112,19 +108,18 @@
             return false;
         }
         final NewIntentItem other = (NewIntentItem) o;
-        return mPause == other.mPause && Objects.equals(mIntents, other.mIntents);
+        return Objects.equals(mIntents, other.mIntents);
     }
 
     @Override
     public int hashCode() {
         int result = 17;
-        result = 31 * result + (mPause ? 1 : 0);
         result = 31 * result + mIntents.hashCode();
         return result;
     }
 
     @Override
     public String toString() {
-        return "NewIntentItem{pause=" + mPause + ",intents=" + mIntents + "}";
+        return "NewIntentItem{intents=" + mIntents + "}";
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b8a741a..31bbd16 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,6 +20,7 @@
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -37,7 +38,6 @@
 import android.content.Context;
 import android.os.BatteryStats;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -61,6 +61,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -650,7 +651,7 @@
 
     private final Object mLock = new Object();
     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
-    private static final Map<BluetoothDevice, List<Pair<MetadataListener, Handler>>>
+    private static final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
                 sMetadataListeners = new HashMap<>();
 
     /**
@@ -660,14 +661,15 @@
     private static final IBluetoothMetadataListener sBluetoothMetadataListener =
             new IBluetoothMetadataListener.Stub() {
         @Override
-        public void onMetadataChanged(BluetoothDevice device, int key, String value) {
+        public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) {
             synchronized (sMetadataListeners) {
                 if (sMetadataListeners.containsKey(device)) {
-                    List<Pair<MetadataListener, Handler>> list = sMetadataListeners.get(device);
-                    for (Pair<MetadataListener, Handler> pair : list) {
-                        MetadataListener listener = pair.first;
-                        Handler handler = pair.second;
-                        handler.post(() -> {
+                    List<Pair<OnMetadataChangedListener, Executor>> list =
+                            sMetadataListeners.get(device);
+                    for (Pair<OnMetadataChangedListener, Executor> pair : list) {
+                        OnMetadataChangedListener listener = pair.first;
+                        Executor executor = pair.second;
+                        executor.execute(() -> {
                             listener.onMetadataChanged(device, key, value);
                         });
                     }
@@ -3153,30 +3155,30 @@
     }
 
     /**
-     * Register a {@link #MetadataListener} to receive update about metadata
+     * Register a {@link #OnMetadataChangedListener} to receive update about metadata
      * changes for this {@link BluetoothDevice}.
      * Registration must be done when Bluetooth is ON and will last until
-     * {@link #unregisterMetadataListener(BluetoothDevice)} is called, even when Bluetooth
+     * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth
      * restarted in the middle.
      * All input parameters should not be null or {@link NullPointerException} will be triggered.
-     * The same {@link BluetoothDevice} and {@link #MetadataListener} pair can only be registered
-     * once, double registration would cause {@link IllegalArgumentException}.
+     * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be
+     * registered once, double registration would cause {@link IllegalArgumentException}.
      *
      * @param device {@link BluetoothDevice} that will be registered
-     * @param listener {@link #MetadataListener} that will receive asynchronous callbacks
-     * @param handler the handler for listener callback
+     * @param executor the executor for listener callback
+     * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks
      * @return true on success, false on error
-     * @throws NullPointerException If one of {@code listener}, {@code device} or {@code handler}
+     * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor}
      * is null.
-     * @throws IllegalArgumentException The same {@link #MetadataListener} and
+     * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and
      * {@link BluetoothDevice} are registered twice.
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean registerMetadataListener(BluetoothDevice device, MetadataListener listener,
-            Handler handler) {
-        if (DBG) Log.d(TAG, "registerMetdataListener()");
+    public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device,
+            @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) {
+        if (DBG) Log.d(TAG, "addOnMetadataChangedListener()");
 
         final IBluetooth service = mService;
         if (service == null) {
@@ -3189,14 +3191,15 @@
         if (device == null) {
             throw new NullPointerException("device is null");
         }
-        if (handler == null) {
-            throw new NullPointerException("handler is null");
+        if (executor == null) {
+            throw new NullPointerException("executor is null");
         }
 
         synchronized (sMetadataListeners) {
-            List<Pair<MetadataListener, Handler>> listenerList = sMetadataListeners.get(device);
+            List<Pair<OnMetadataChangedListener, Executor>> listenerList =
+                    sMetadataListeners.get(device);
             if (listenerList == null) {
-                // Create new listener/handler list for registeration
+                // Create new listener/executor list for registeration
                 listenerList = new ArrayList<>();
                 sMetadataListeners.put(device, listenerList);
             } else {
@@ -3207,7 +3210,7 @@
                 }
             }
 
-            Pair<MetadataListener, Handler> listenerPair = new Pair(listener, handler);
+            Pair<OnMetadataChangedListener, Executor> listenerPair = new Pair(listener, executor);
             listenerList.add(listenerPair);
 
             boolean ret = false;
@@ -3230,63 +3233,74 @@
     }
 
     /**
-     * Unregister all {@link MetadataListener} from this {@link BluetoothDevice}.
+     * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}.
      * Unregistration can be done when Bluetooth is either ON or OFF.
-     * {@link #registerMetadataListener(MetadataListener, BluetoothDevice, Handler)} must
-     * be called before unregisteration.
-     * Unregistering a device that is not regestered would cause {@link IllegalArgumentException}.
+     * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)}
+     * must be called before unregisteration.
      *
-     * @param device {@link BluetoothDevice} that will be unregistered. it
+     * @param device {@link BluetoothDevice} that will be unregistered. It
+     * should not be null or {@link NullPointerException} will be triggered.
+     * @param listener {@link OnMetadataChangedListener} that will be unregistered. It
      * should not be null or {@link NullPointerException} will be triggered.
      * @return true on success, false on error
-     * @throws NullPointerException If {@code device} is null.
+     * @throws NullPointerException If {@code listener} or {@code device} is null.
      * @throws IllegalArgumentException If {@code device} has not been registered before.
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean unregisterMetadataListener(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "unregisterMetdataListener()");
+    public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device,
+            @NonNull OnMetadataChangedListener listener) {
+        if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()");
         if (device == null) {
             throw new NullPointerException("device is null");
         }
+        if (listener == null) {
+            throw new NullPointerException("listener is null");
+        }
 
         synchronized (sMetadataListeners) {
-            if (sMetadataListeners.containsKey(device)) {
-                sMetadataListeners.remove(device);
-            } else {
+            if (!sMetadataListeners.containsKey(device)) {
                 throw new IllegalArgumentException("device was not registered");
             }
+            // Remove issued listener from the registered device
+            sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener)));
 
-            final IBluetooth service = mService;
-            if (service == null) {
-                // Bluetooth is OFF, do nothing to Bluetooth service.
-                return true;
-            }
-            try {
-                return service.unregisterMetadataListener(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "unregisterMetadataListener fail", e);
-                return false;
+            if (sMetadataListeners.get(device).isEmpty()) {
+                // Unregister to Bluetooth service if all listeners are removed from
+                // the registered device
+                sMetadataListeners.remove(device);
+                final IBluetooth service = mService;
+                if (service == null) {
+                    // Bluetooth is OFF, do nothing to Bluetooth service.
+                    return true;
+                }
+                try {
+                    return service.unregisterMetadataListener(device);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "unregisterMetadataListener fail", e);
+                    return false;
+                }
             }
         }
+        return true;
     }
 
     /**
-     * This abstract class is used to implement {@link BluetoothAdapter} metadata listener.
+     * This interface is used to implement {@link BluetoothAdapter} metadata listener.
      * @hide
      */
     @SystemApi
-    public abstract static class MetadataListener {
+    public interface OnMetadataChangedListener {
         /**
          * Callback triggered if the metadata of {@link BluetoothDevice} registered in
-         * {@link #registerMetadataListener}.
+         * {@link #addOnMetadataChangedListener}.
          *
          * @param device changed {@link BluetoothDevice}.
          * @param key changed metadata key, one of BluetoothDevice.METADATA_*.
-         * @param value the new value of metadata.
+         * @param value the new value of metadata as byte array.
          */
-        public void onMetadataChanged(BluetoothDevice device, int key, String value) {
-        }
+        void onMetadataChanged(@NonNull BluetoothDevice device, int key,
+                @Nullable byte[] value);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 204d7e3..74ceeb9 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -351,6 +352,7 @@
 
     /**
      * Manufacturer name of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -358,6 +360,7 @@
 
     /**
      * Model name of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -365,6 +368,7 @@
 
     /**
      * Software version of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -372,6 +376,7 @@
 
     /**
      * Hardware version of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -379,6 +384,7 @@
 
     /**
      * Package name of the companion app, if any
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -386,6 +392,7 @@
 
     /**
      * URI to the main icon shown on the settings UI
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -393,80 +400,91 @@
 
     /**
      * Whether this device is an untethered headset with left, right and case
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_IS_UNTHETHERED_HEADSET = 6;
+    public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
 
     /**
      * URI to icon of the left headset
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_LEFT_ICON = 7;
+    public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
 
     /**
      * URI to icon of the right headset
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8;
+    public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
 
     /**
      * URI to icon of the headset charging case
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_CASE_ICON = 9;
+    public static final int METADATA_UNTETHERED_CASE_ICON = 9;
 
     /**
-     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
-     * is invalid, of the left headset
+     * Battery level of left headset
+     * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+     * as invalid.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10;
+    public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
 
     /**
-     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
-     * is invalid, of the right headset
+     * Battery level of rigth headset
+     * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+     * as invalid.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11;
+    public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
 
     /**
-     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
-     * is invalid, of the headset charging case
+     * Battery level of the headset charging case
+     * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+     * as invalid.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12;
+    public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
 
     /**
      * Whether the left headset is charging
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13;
+    public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
 
     /**
      * Whether the right headset is charging
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14;
+    public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
 
     /**
      * Whether the headset charging case is charging
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15;
+    public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
 
     /**
-     * URI to the enhanced settings UI slice, null or empty String means
-     * the UI does not exist
+     * URI to the enhanced settings UI slice
+     * Data type should be {@String} as {@link Byte} array, null means
+     * the UI does not exist.
      * @hide
      */
     @SystemApi
@@ -2243,21 +2261,21 @@
      * {@link #BOND_NONE}.
      *
      * @param key must be within the list of BluetoothDevice.METADATA_*
-     * @param value the string data to set for key. Must be less than
+     * @param value a byte array data to set for key. Must be less than
      * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
      * @return true on success, false on error
      * @hide
     */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean setMetadata(int key, String value) {
+    public boolean setMetadata(int key, @NonNull byte[] value) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
             return false;
         }
-        if (value.length() > METADATA_MAX_LENGTH) {
-            throw new IllegalArgumentException("value length is " + value.length()
+        if (value.length > METADATA_MAX_LENGTH) {
+            throw new IllegalArgumentException("value length is " + value.length
                     + ", should not over " + METADATA_MAX_LENGTH);
         }
         try {
@@ -2272,12 +2290,13 @@
      * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
      *
      * @param key must be within the list of BluetoothDevice.METADATA_*
-     * @return Metadata of the key as string, null on error or not found
+     * @return Metadata of the key as byte array, null on error or not found
      * @hide
      */
     @SystemApi
+    @Nullable
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public String getMetadata(int key) {
+    public byte[] getMetadata(int key) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 791c551..00f1e43 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3398,7 +3398,7 @@
      *
      * @param mimeType Valid, concrete MIME type.
      */
-    public final @NonNull TypeInfo getTypeInfo(@NonNull String mimeType) {
+    public final @NonNull MimeTypeInfo getTypeInfo(@NonNull String mimeType) {
         Objects.requireNonNull(mimeType);
         return MimeIconUtils.getTypeInfo(mimeType);
     }
@@ -3407,13 +3407,13 @@
      * Detailed description of a specific MIME type, including an icon and label
      * that describe the type.
      */
-    public static final class TypeInfo {
+    public static final class MimeTypeInfo {
         private final Icon mIcon;
         private final CharSequence mLabel;
         private final CharSequence mContentDescription;
 
         /** {@hide} */
-        public TypeInfo(@NonNull Icon icon, @NonNull CharSequence label,
+        public MimeTypeInfo(@NonNull Icon icon, @NonNull CharSequence label,
                 @NonNull CharSequence contentDescription) {
             mIcon = Objects.requireNonNull(icon);
             mLabel = Objects.requireNonNull(label);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d87171e..8628d32 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4731,6 +4731,18 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
 
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the files application.
+     * The activity should be able to browse and manage files stored on the device.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String)} to generate a main
+     * Intent with this category in the selector.</p>
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard extra data keys.
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index fc79a42..639335e 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -451,7 +451,7 @@
     public String toString() {
         return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName
                 + ((targetOverlayableName == null) ? ""
-                : ", targetOverlyabale=" + targetOverlayableName)
+                : ", targetOverlayable=" + targetOverlayableName)
                 + ", state=" + state + " (" + stateToString(state) + "), userId=" + userId + " }";
     }
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 7fe840c..a71f7d2 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -30,7 +30,6 @@
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.PackageManager.DeleteFlags;
 import android.content.pm.PackageManager.InstallReason;
@@ -504,12 +503,14 @@
      *
      * <p>Staged session is active iff:
      * <ul>
-     *     <li>It is committed.
-     *     <li>It is not applied.
-     *     <li>It is not failed.
+     *     <li>It is committed, i.e. {@link SessionInfo#isCommitted()} is {@code true}, and
+     *     <li>it is not applied, i.e. {@link SessionInfo#isStagedSessionApplied()} is {@code
+     *     false}, and
+     *     <li>it is not failed, i.e. {@link SessionInfo#isStagedSessionFailed()} is {@code false}.
      * </ul>
      *
-     * <p>In case of a multi-apk session, parent session will be returned.
+     * <p>In case of a multi-apk session, reasoning above is applied to the parent session, since
+     * that is the one that should been {@link Session#commit committed}.
      */
     public @Nullable SessionInfo getActiveStagedSession() {
         final List<SessionInfo> stagedSessions = getStagedSessions();
@@ -2307,7 +2308,8 @@
         }
 
         /**
-         * Whenever this session was committed.
+         * Returns {@code true} if {@link Session#commit(IntentSender)}} was called for this
+         * session.
          */
         public boolean isCommitted() {
             return isCommitted;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2b23e7a..bdd80e32 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1602,8 +1602,8 @@
         final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
 
         XmlResourceParser parser = null;
+        ApkAssets apkAssets = null;
         try {
-            final ApkAssets apkAssets;
             try {
                 apkAssets = fd != null
                         ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
@@ -1640,7 +1640,13 @@
                     "Failed to parse " + apkPath, e);
         } finally {
             IoUtils.closeQuietly(parser);
-            // TODO(b/72056911): Implement and call close() on ApkAssets.
+            if (apkAssets != null) {
+                try {
+                    apkAssets.close();
+                } catch (Throwable ignored) {
+                }
+            }
+            // TODO(b/72056911): Implement AutoCloseable on ApkAssets.
         }
     }
 
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index dc1d052..69462ab 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -36,7 +36,9 @@
  */
 public final class ApkAssets {
     @GuardedBy("this") private final long mNativePtr;
-    @GuardedBy("this") private StringBlock mStringBlock;
+    @GuardedBy("this") private final StringBlock mStringBlock;
+
+    @GuardedBy("this") private boolean mOpen = true;
 
     /**
      * Creates a new ApkAssets instance from the given path on disk.
@@ -180,7 +182,20 @@
 
     @Override
     protected void finalize() throws Throwable {
-        nativeDestroy(mNativePtr);
+        close();
+    }
+
+    /**
+     * Closes this class and the contained {@link #mStringBlock}.
+     */
+    public void close() throws Throwable {
+        synchronized (this) {
+            if (mOpen) {
+                mOpen = false;
+                mStringBlock.close();
+                nativeDestroy(mNativePtr);
+            }
+        }
     }
 
     private static native long nativeLoad(
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index b5ec0f9..b7bc822 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -18,13 +18,34 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Color;
-import android.text.*;
-import android.text.style.*;
-import android.util.Log;
-import android.util.SparseArray;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Typeface;
+import android.text.Annotation;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannedString;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.BulletSpan;
+import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.LineHeightSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StrikethroughSpan;
+import android.text.style.StyleSpan;
+import android.text.style.SubscriptSpan;
+import android.text.style.SuperscriptSpan;
+import android.text.style.TextAppearanceSpan;
+import android.text.style.TypefaceSpan;
+import android.text.style.URLSpan;
+import android.text.style.UnderlineSpan;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
 
 import java.util.Arrays;
 
@@ -40,8 +61,12 @@
     private final long mNative;
     private final boolean mUseSparse;
     private final boolean mOwnsNative;
+
     private CharSequence[] mStrings;
     private SparseArray<CharSequence> mSparseStrings;
+
+    @GuardedBy("this") private boolean mOpen = true;
+
     StyleIDs mStyleIDs = null;
 
     public StringBlock(byte[] data, boolean useSparse) {
@@ -141,12 +166,23 @@
         }
     }
 
+    @Override
     protected void finalize() throws Throwable {
         try {
             super.finalize();
         } finally {
-            if (mOwnsNative) {
-                nativeDestroy(mNative);
+            close();
+        }
+    }
+
+    public void close() throws Throwable {
+        synchronized (this) {
+            if (mOpen) {
+                mOpen = false;
+
+                if (mOwnsNative) {
+                    nativeDestroy(mNative);
+                }
             }
         }
     }
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 014bc24..3523e95 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -52,7 +52,7 @@
     private static final Pattern sLimitPattern =
             Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
     private static final Pattern sAggregationPattern = Pattern.compile(
-            "(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL)\\((.+)\\)");
+            "(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL|GROUP_CONCAT)\\((.+)\\)");
 
     private Map<String, String> mProjectionMap = null;
     private List<Pattern> mProjectionGreylist = null;
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index a696eeb..6c497d4 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -207,5 +207,22 @@
             Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected");
         }
     }
+
+    /**
+     * TODO(b/123378871): Remove when moved.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback) {
+        if (mService != null) {
+            try {
+                mService.registerCancellationCallback(callback);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "registerCancellationCallback(): Service not connected");
+        }
+    }
 }
 
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 08035972..1142a07 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -82,6 +82,11 @@
      * @hide
      */
     public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential";
+    /**
+     * @hide
+     */
+    public static final String KEY_FROM_CONFIRM_DEVICE_CREDENTIAL
+            = "from_confirm_device_credential";
 
     /**
      * Error/help message will show for this amount of time.
@@ -271,6 +276,17 @@
         }
 
         /**
+         * TODO(123378871): Remove when moved.
+         * @return
+         * @hide
+         */
+        @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+        @NonNull public Builder setFromConfirmDeviceCredential() {
+            mBundle.putBoolean(KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, true);
+            return this;
+        }
+
+        /**
          * Creates a {@link BiometricPrompt}.
          * @return a {@link BiometricPrompt}
          * @throws IllegalArgumentException if any of the required fields are not set.
@@ -494,7 +510,8 @@
     public void authenticateUser(@NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AuthenticationCallback callback,
-            int userId) {
+            int userId,
+            IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) {
         if (cancel == null) {
             throw new IllegalArgumentException("Must supply a cancellation signal");
         }
@@ -504,7 +521,8 @@
         if (callback == null) {
             throw new IllegalArgumentException("Must supply a callback");
         }
-        authenticateInternal(null /* crypto */, cancel, executor, callback, userId);
+        authenticateInternal(null /* crypto */, cancel, executor, callback, userId,
+                confirmDeviceCredentialCallback);
     }
 
     /**
@@ -555,7 +573,8 @@
         if (mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL)) {
             throw new IllegalArgumentException("Device credential not supported with crypto");
         }
-        authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
+        authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId(),
+                null /* confirmDeviceCredentialCallback */);
     }
 
     /**
@@ -597,7 +616,8 @@
         if (callback == null) {
             throw new IllegalArgumentException("Must supply a callback");
         }
-        authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
+        authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId(),
+                null /* confirmDeviceCredentialCallback */);
     }
 
     private void cancelAuthentication() {
@@ -614,7 +634,8 @@
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AuthenticationCallback callback,
-            int userId) {
+            int userId,
+            IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) {
         try {
             if (cancel.isCanceled()) {
                 Log.w(TAG, "Authentication already canceled");
@@ -629,7 +650,7 @@
             final long sessionId = crypto != null ? crypto.getOpId() : 0;
             if (BiometricManager.hasBiometrics(mContext)) {
                 mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
-                        mContext.getOpPackageName(), mBundle);
+                        mContext.getOpPackageName(), mBundle, confirmDeviceCredentialCallback);
             } else {
                 mExecutor.execute(() -> {
                     callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT,
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
index 496d9c5..787dc66 100644
--- a/core/java/android/hardware/biometrics/CryptoObject.java
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -25,8 +25,8 @@
 import javax.crypto.Mac;
 
 /**
- * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
- * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+ * A wrapper class for the crypto objects supported by BiometricPrompt and FingerprintManager.
+ * Currently the framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
  * @hide
  */
 public class CryptoObject {
diff --git a/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl b/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl
new file mode 100644
index 0000000..8b35852
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+/**
+ * Communication channel between ConfirmDeviceCredential / ConfirmLock* and BiometricService.
+ * @hide
+ */
+interface IBiometricConfirmDeviceCredentialCallback {
+    // Invoked when authentication should be canceled.
+    oneway void cancel();
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 4971911..90d4921 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -17,6 +17,7 @@
 package android.hardware.biometrics;
 
 import android.os.Bundle;
+import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricServiceReceiver;
 
@@ -30,8 +31,10 @@
 interface IBiometricService {
     // Requests authentication. The service choose the appropriate biometric to use, and show
     // the corresponding BiometricDialog.
+    // TODO(b/123378871): Remove callback when moved.
     void authenticate(IBinder token, long sessionId, int userId,
-            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle);
+            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle,
+            IBiometricConfirmDeviceCredentialCallback callback);
 
     // Cancel authentication for the given sessionId
     void cancelAuthentication(IBinder token, String opPackageName);
@@ -59,4 +62,8 @@
     void onConfirmDeviceCredentialSuccess();
     // TODO(b/123378871): Remove when moved.
     void onConfirmDeviceCredentialError(int error, String message);
+    // TODO(b/123378871): Remove when moved.
+    // When ConfirmLock* is invoked from BiometricPrompt, it needs to register a callback so that
+    // it can receive the cancellation signal.
+    void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback);
 }
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 8231985..c955137 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -25,6 +25,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 
 /**
@@ -64,13 +65,12 @@
     public abstract boolean isProximitySensorAvailable();
 
     /**
-     * Take a screenshot of the specified display into the provided {@link Surface}.
+     * Take a screenshot of the specified display and return a buffer.
      *
      * @param displayId The display id to take the screenshot of.
-     * @param outSurface The {@link Surface} to take the screenshot into.
-     * @return True if the screenshot is taken.
+     * @return The buffer or null if we have failed.
      */
-    public abstract boolean screenshot(int displayId, Surface outSurface);
+    public abstract SurfaceControl.ScreenshotGraphicBuffer screenshot(int displayId);
 
     /**
      * Returns information about the specified logical display.
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index dbb894f..a46c410 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -15,9 +15,16 @@
  */
 package android.net;
 
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.content.Context;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 /**
  *
  * Constants for client code communicating with the network stack service.
@@ -37,4 +44,52 @@
             "android.permission.MAINLINE_NETWORK_STACK";
 
     private NetworkStack() {}
+
+    /**
+     * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a
+     * {@link SecurityException}.
+     *
+     * @param context {@link android.content.Context} for the process.
+     *
+     * @hide
+     */
+    public static void checkNetworkStackPermission(final @NonNull Context context) {
+        checkNetworkStackPermissionOr(context);
+    }
+
+    /**
+     * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed
+     * for a particular process, throw a {@link SecurityException}.
+     *
+     * @param context {@link android.content.Context} for the process.
+     * @param otherPermissions The set of permissions that could be the candidate permissions , or
+     *                         empty string if none of other permissions needed.
+     * @hide
+     */
+    public static void checkNetworkStackPermissionOr(final @NonNull Context context,
+            final @NonNull String... otherPermissions) {
+        ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions));
+        permissions.add(NETWORK_STACK);
+        permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
+        enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
+    }
+
+    private static void enforceAnyPermissionOf(final @NonNull Context context,
+            final @NonNull String... permissions) {
+        if (!checkAnyPermissionOf(context, permissions)) {
+            throw new SecurityException("Requires one of the following permissions: "
+                + String.join(", ", permissions) + ".");
+        }
+    }
+
+    private static boolean checkAnyPermissionOf(final @NonNull Context context,
+            final @NonNull String... permissions) {
+        for (String permission : permissions) {
+            if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 9e9e68d..ed5c1b1 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -1148,9 +1148,9 @@
         final Context context = AppGlobals.getInitialApplication();
         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
 
-        final boolean hasLegacy = appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
+        final boolean hasLegacy = appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
                 context.getApplicationInfo().uid,
-                context.getPackageName()) == AppOpsManager.MODE_ALLOWED;
+                context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
 
         // STOPSHIP: only use app-op once permission model has fully landed
         final boolean requestedLegacy = !AppGlobals.getInitialApplication().getApplicationInfo()
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 53503f4..e56b6e0 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -188,11 +188,16 @@
 
                     if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
                         Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
-                        final String paths = getDebugLayerAppPaths(pm, gpuDebugLayerApp);
-                        if (paths != null) {
-                            // Append the path so files placed in the app's base directory will
-                            // override the external path
-                            layerPaths += paths + ":";
+                        // If a colon is present, treat this as multiple apps, so Vulkan and GLES
+                        // layer apps can be provided at the same time.
+                        String[] layerApps = gpuDebugLayerApp.split(":");
+                        for (int i = 0; i < layerApps.length; i++) {
+                            String paths = getDebugLayerAppPaths(pm, layerApps[i]);
+                            if (paths != null) {
+                                // Append the path so files placed in the app's base directory will
+                                // override the external path
+                                layerPaths += paths + ":";
+                            }
                         }
                     }
 
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index bd70f23..ab19fd6 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -646,9 +646,14 @@
                 ZygoteConfig.USAP_POOL_ENABLED, USAP_POOL_ENABLED_DEFAULT);
 
         if (!propertyString.isEmpty()) {
-            mUsapPoolEnabled = Zygote.getConfigurationPropertyBoolean(
+            if (SystemProperties.get("dalvik.vm.boot-image", "").endsWith("apex.art")) {
+                // TODO(b/119800099): Tweak usap configuration in jitzygote mode.
+                mUsapPoolEnabled = false;
+            } else {
+                mUsapPoolEnabled = Zygote.getConfigurationPropertyBoolean(
                     ZygoteConfig.USAP_POOL_ENABLED,
                     Boolean.parseBoolean(USAP_POOL_ENABLED_DEFAULT));
+            }
         }
 
         boolean valueChanged = origVal != mUsapPoolEnabled;
diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 8f68723..f1f24fb 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -211,7 +211,7 @@
      * Intent Keys
      */
     /**
-     * Intent key: Size of system image, in bytes.
+     * Intent key: Size of the system image, in bytes.
      * @hide
      */
     public static final String KEY_SYSTEM_SIZE = "KEY_SYSTEM_SIZE";
@@ -365,7 +365,7 @@
      *
      * This function doesn't require prior calling {@link #bind}.
      *
-     * @param systemUrl A network URL or a file URL to system image.
+     * @param systemUrl a network Uri, a file Uri or a content Uri pointing to a system image file.
      * @param systemSize size of system image.
      */
     @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM)
@@ -381,7 +381,7 @@
      *
      * This function doesn't require prior calling {@link #bind}.
      *
-     * @param systemUrl A network URL or a file URL to system image.
+     * @param systemUrl a network Uri, a file Uri or a content Uri pointing to a system image file.
      * @param systemSize size of system image.
      * @param userdataSize bytes reserved for userdata.
      */
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index c57bf91..080ff73 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1130,7 +1130,7 @@
     public @NonNull StorageVolume getStorageVolume(@NonNull Uri uri) {
         final String volumeName = MediaStore.getVolumeName(uri);
         switch (volumeName) {
-            case MediaStore.VOLUME_EXTERNAL:
+            case MediaStore.VOLUME_EXTERNAL_PRIMARY:
                 return getPrimaryStorageVolume();
             default:
                 for (StorageVolume vol : getStorageVolumes()) {
@@ -1652,6 +1652,26 @@
      */
     public static boolean checkPermissionAndAppOp(Context context, boolean enforce,
             int pid, int uid, String packageName, String permission, int op) {
+        return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, permission, op,
+                true);
+    }
+
+    /**
+     * Check that given app holds both permission and appop but do not noteOp.
+     * @hide
+     */
+    public static boolean checkPermissionAndCheckOp(Context context, boolean enforce,
+            int pid, int uid, String packageName, String permission, int op) {
+        return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, permission, op,
+                false);
+    }
+
+    /**
+     * Check that given app holds both permission and appop.
+     * @hide
+     */
+    private static boolean checkPermissionAndAppOp(Context context, boolean enforce,
+            int pid, int uid, String packageName, String permission, int op, boolean note) {
         if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
             if (enforce) {
                 throw new SecurityException(
@@ -1662,7 +1682,21 @@
         }
 
         AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
-        final int mode = appOps.noteOpNoThrow(op, uid, packageName);
+        final int mode;
+        if (note) {
+            mode = appOps.noteOpNoThrow(op, uid, packageName);
+        } else {
+            try {
+                appOps.checkPackage(uid, packageName);
+            } catch (SecurityException e) {
+                if (enforce) {
+                    throw e;
+                } else {
+                    return false;
+                }
+            }
+            mode = appOps.checkOpNoThrow(op, uid, packageName);
+        }
         switch (mode) {
             case AppOpsManager.MODE_ALLOWED:
                 return true;
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 225ecfa..6280600 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -265,8 +265,13 @@
     }
 
     /** {@hide} */
+    public static @Nullable String normalizeUuid(@Nullable String fsUuid) {
+        return fsUuid != null ? fsUuid.toLowerCase(Locale.US) : null;
+    }
+
+    /** {@hide} */
     public @Nullable String getNormalizedUuid() {
-        return mFsUuid != null ? mFsUuid.toLowerCase(Locale.US) : null;
+        return normalizeUuid(mFsUuid);
     }
 
     /**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index bda6ed1..da19d59 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -102,20 +102,40 @@
     public static final @NonNull Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     /**
-     * Volume name used for content on "internal" storage of device. This
-     * volume contains media distributed with the device, such as built-in
-     * ringtones and wallpapers.
+     * Synthetic volume name that provides a view of all content across the
+     * "internal" storage of the device.
+     * <p>
+     * This synthetic volume provides a merged view of all media distributed
+     * with the device, such as built-in ringtones and wallpapers.
+     * <p>
+     * Because this is a synthetic volume, you can't insert new content into
+     * this volume.
      */
     public static final String VOLUME_INTERNAL = "internal";
 
     /**
-     * Volume name used for content on "external" storage of device. This only
-     * includes media on the primary shared storage device; the contents of any
-     * secondary storage devices can be obtained using
-     * {@link #getAllVolumeNames(Context)}.
+     * Synthetic volume name that provides a view of all content across the
+     * "external" storage of the device.
+     * <p>
+     * This synthetic volume provides a merged view of all media across all
+     * currently attached external storage devices.
+     * <p>
+     * Because this is a synthetic volume, you can't insert new content into
+     * this volume. Instead, you can insert content into a specific storage
+     * volume obtained from {@link #getExternalVolumeNames(Context)}.
      */
     public static final String VOLUME_EXTERNAL = "external";
 
+    /**
+     * Specific volume name that represents the primary external storage device
+     * at {@link Environment#getExternalStorageDirectory()}.
+     * <p>
+     * This volume may not always be available, such as when the user has
+     * ejected the device. You can find a list of all specific volume names
+     * using {@link #getExternalVolumeNames(Context)}.
+     */
+    public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
+
     /** {@hide} */
     public static final String SCAN_FILE_CALL = "scan_file";
     /** {@hide} */
@@ -1037,6 +1057,16 @@
         public static final String OWNER_PACKAGE_NAME = "owner_package_name";
 
         /**
+         * Volume name of the specific storage device where this media item is
+         * persisted. The value is typically one of the volume names returned
+         * from {@link MediaStore#getExternalVolumeNames(Context)}.
+         * <p>
+         * This is a read-only column that is automatically computed.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String VOLUME_NAME = "volume_name";
+
+        /**
          * Relative path of this media item within the storage device where it
          * is persisted. For example, an item stored at
          * {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
@@ -1408,7 +1438,7 @@
             final StorageVolume sv = sm.getStorageVolume(path);
             if (sv != null) {
                 if (sv.isPrimary()) {
-                    return VOLUME_EXTERNAL;
+                    return VOLUME_EXTERNAL_PRIMARY;
                 } else {
                     return checkArgumentVolumeName(sv.getNormalizedUuid());
                 }
@@ -1710,7 +1740,7 @@
                 String stringUrl = null;    /* value to be returned */
 
                 try {
-                    url = cr.insert(EXTERNAL_CONTENT_URI, values);
+                    url = cr.insert(getContentUri(VOLUME_EXTERNAL_PRIMARY), values);
 
                     if (source != null) {
                         try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
@@ -2676,7 +2706,13 @@
             public static final String ALBUM = "album";
 
             /**
-             * The artist whose songs appear on this album
+             * The ID of the artist whose songs appear on this album.
+             */
+            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+            public static final String ARTIST_ID = "artist_id";
+
+            /**
+             * The name of the artist whose songs appear on this album.
              */
             @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
             public static final String ARTIST = "artist";
@@ -3218,22 +3254,29 @@
         }
     }
 
-    /**
-     * Return list of all volume names currently available. This includes a
-     * unique name for each shared storage device that is currently mounted.
-     * <p>
-     * Each name can be passed to APIs like
-     * {@link MediaStore.Images.Media#getContentUri(String)} to query media at
-     * that location.
-     */
+    /** @removed */
+    @Deprecated
     public static @NonNull Set<String> getAllVolumeNames(@NonNull Context context) {
+        return getExternalVolumeNames(context);
+    }
+
+    /**
+     * Return list of all specific volume names that make up
+     * {@link #VOLUME_EXTERNAL}. This includes a unique volume name for each
+     * shared storage device that is currently attached, which typically
+     * includes {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}.
+     * <p>
+     * Each specific volume name can be passed to APIs like
+     * {@link MediaStore.Images.Media#getContentUri(String)} to interact with
+     * media on that storage device.
+     */
+    public static @NonNull Set<String> getExternalVolumeNames(@NonNull Context context) {
         final StorageManager sm = context.getSystemService(StorageManager.class);
         final Set<String> volumeNames = new ArraySet<>();
-        volumeNames.add(VOLUME_INTERNAL);
         for (VolumeInfo vi : sm.getVolumes()) {
             if (vi.isVisibleForUser(UserHandle.myUserId()) && vi.isMountedReadable()) {
                 if (vi.isPrimary()) {
-                    volumeNames.add(VOLUME_EXTERNAL);
+                    volumeNames.add(VOLUME_EXTERNAL_PRIMARY);
                 } else {
                     volumeNames.add(vi.getNormalizedFsUuid());
                 }
@@ -3264,6 +3307,8 @@
             return volumeName;
         } else if (VOLUME_EXTERNAL.equals(volumeName)) {
             return volumeName;
+        } else if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName)) {
+            return volumeName;
         }
 
         // When not one of the well-known values above, it must be a hex UUID
@@ -3279,8 +3324,9 @@
     }
 
     /**
-     * Return path where the given volume is mounted. Not valid for
-     * {@link #VOLUME_INTERNAL}.
+     * Return path where the given specific volume is mounted. Not valid for
+     * {@link #VOLUME_INTERNAL} or {@link #VOLUME_EXTERNAL}, since those are
+     * broad collections that cover many paths.
      *
      * @hide
      */
@@ -3291,8 +3337,12 @@
             throw new IllegalArgumentException();
         }
 
-        if (VOLUME_EXTERNAL.equals(volumeName)) {
-            return Environment.getExternalStorageDirectory();
+        switch (volumeName) {
+            case VOLUME_INTERNAL:
+            case VOLUME_EXTERNAL:
+                throw new FileNotFoundException(volumeName + " has no associated path");
+            case VOLUME_EXTERNAL_PRIMARY:
+                return Environment.getExternalStorageDirectory();
         }
 
         final StorageManager sm = AppGlobals.getInitialApplication()
@@ -3322,23 +3372,31 @@
             throw new IllegalArgumentException();
         }
 
+        final Context context = AppGlobals.getInitialApplication();
+        final UserManager um = context.getSystemService(UserManager.class);
+
         final ArrayList<File> res = new ArrayList<>();
         if (VOLUME_INTERNAL.equals(volumeName)) {
-            addCanoncialFile(res, new File(Environment.getRootDirectory(), "media"));
-            addCanoncialFile(res, new File(Environment.getOemDirectory(), "media"));
-            addCanoncialFile(res, new File(Environment.getProductDirectory(), "media"));
+            addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
+            addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
+            addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
+        } else if (VOLUME_EXTERNAL.equals(volumeName)) {
+            for (String exactVolume : getExternalVolumeNames(context)) {
+                addCanonicalFile(res, getVolumePath(exactVolume));
+            }
+            if (um.isDemoUser()) {
+                addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
+            }
         } else {
-            addCanoncialFile(res, getVolumePath(volumeName));
-            final UserManager um = AppGlobals.getInitialApplication()
-                    .getSystemService(UserManager.class);
-            if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) {
-                addCanoncialFile(res, Environment.getDataPreloadsMediaDirectory());
+            addCanonicalFile(res, getVolumePath(volumeName));
+            if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName) && um.isDemoUser()) {
+                addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
             }
         }
         return res;
     }
 
-    private static void addCanoncialFile(List<File> list, File file) {
+    private static void addCanonicalFile(List<File> list, File file) {
         try {
             list.add(file.getCanonicalFile());
         } catch (IOException e) {
@@ -3376,12 +3434,12 @@
      * <p>
      * No other assumptions should be made about the meaning of the version.
      * <p>
-     * This method returns the version for {@link MediaStore#VOLUME_EXTERNAL};
-     * to obtain a version for a different volume, use
-     * {@link #getVersion(Context, String)}.
+     * This method returns the version for
+     * {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}; to obtain a version for a
+     * different volume, use {@link #getVersion(Context, String)}.
      */
     public static @NonNull String getVersion(@NonNull Context context) {
-        return getVersion(context, VOLUME_EXTERNAL);
+        return getVersion(context, VOLUME_EXTERNAL_PRIMARY);
     }
 
     /**
@@ -3395,7 +3453,7 @@
      *
      * @param volumeName specific volume to obtain an opaque version string for.
      *            Must be one of the values returned from
-     *            {@link #getAllVolumeNames(Context)}.
+     *            {@link #getExternalVolumeNames(Context)}.
      */
     public static @NonNull String getVersion(@NonNull Context context, @NonNull String volumeName) {
         final ContentResolver resolver = context.getContentResolver();
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index 42c2d5c..5f8266d 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.ContentResolver;
 
@@ -210,6 +211,7 @@
     /**
      * Cursor schema for SliceUriPairs.
      */
+    @NonNull
     public static final String[] SLICE_URI_PAIRS_COLUMNS = new String[]{
             SliceUriPairColumns.KEY,
             SliceUriPairColumns.SLICE_URI
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index d505f02..da29e2e 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.slice.Slice;
 import android.content.ContentProvider;
@@ -184,6 +185,7 @@
      * Returns a {@link Cursor} linking {@link Slice} {@link Uri Uris} to the
      * corresponding Settings key.
      */
+    @Nullable
     public Cursor querySliceUriPairs() {
         // By default no-op;
         return null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3db6b2b..e3b2d89 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -955,6 +955,20 @@
             "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
 
     /**
+     * Activity Action: Open the advanced power usage details page of an associated app.
+     * <p>
+     * Input: Intent's data URI set with an application name, using the
+     * "package" schema (like "package:com.my.app")
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL =
+            "android.settings.VIEW_ADVANCED_POWER_USAGE_DETAIL";
+
+    /**
      * Activity Action: Show screen for controlling background data
      * restrictions for a particular application.
      * <p>
@@ -11199,62 +11213,6 @@
         public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
 
         /**
-         * The threshold value for the number of consecutive dns timeout events received to be a
-         * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this
-         * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note
-         * that the value should be {@code > 0} if the DNS data stall detection is enabled.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
-                "data_stall_consecutive_dns_timeout_threshold";
-
-        /**
-         * The minimal time interval in milliseconds for data stall reevaluation.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_MIN_EVALUATE_INTERVAL =
-                "data_stall_min_evaluate_interval";
-
-        /**
-         * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting
-         * a data stall.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD =
-                "data_stall_valid_dns_time_threshold";
-
-        /**
-         * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing
-         * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values.
-         *
-         * Type: int
-         * Valid values:
-         *   {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal.
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-
-        /**
-         * Use dns timeout counts to detect data stall.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
-
-        /**
          * Whether to try cellular data recovery when a bad network is reported.
          *
          * @hide
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index f39ef9a..5a91802 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -674,6 +674,8 @@
      * Called when the Android system disconnects from the service.
      *
      * <p> At this point this service may no longer be an active {@link AutofillService}.
+     * It should not make calls on {@link AutofillManager} that requires the caller to be
+     * the current service.
      */
     public void onDisconnected() {
     }
@@ -695,6 +697,8 @@
      * finishing the {@link FillCallback}.
      *
      * @return The history or {@code null} if there are no events.
+     *
+     * @throws RuntimeException if the event history could not be retrieved.
      */
     @Nullable public final FillEventHistory getFillEventHistory() {
         final AutofillManager afm = getSystemService(AutofillManager.class);
diff --git a/core/java/android/service/autofill/IFillCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl
index 1bad1d7..32cf712 100644
--- a/core/java/android/service/autofill/IFillCallback.aidl
+++ b/core/java/android/service/autofill/IFillCallback.aidl
@@ -25,7 +25,7 @@
  *
  * @hide
  */
-interface IFillCallback {
+oneway interface IFillCallback {
     void onCancellable(in ICancellationSignal cancellation);
     void onSuccess(in FillResponse response);
     void onFailure(int requestId, CharSequence message);
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 96b861b..b00eb8a 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -41,6 +41,7 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAugmentedAutofillManagerClient;
 import android.view.autofill.IAutofillWindowPresenter;
@@ -183,6 +184,8 @@
      * Called when the Android system disconnects from the service.
      *
      * <p> At this point this service may no longer be an active {@link AugmentedAutofillService}.
+     * It should not make calls on {@link AutofillManager} that requires the caller to be
+     * the current service.
      */
     public void onDisconnected() {
     }
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index dc57a15..5be73b9 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -37,7 +37,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.service.autofill.AutofillService;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -350,7 +349,9 @@
     /**
      * Called when the Android system disconnects from the service.
      *
-     * <p> At this point this service may no longer be an active {@link AutofillService}.
+     * <p> At this point this service may no longer be an active {@link ContentCaptureService}.
+     * It should not make calls on {@link ContentCaptureManager} that requires the caller to be
+     * the current service.
      */
     public void onDisconnected() {
         Slog.i(TAG, "unbinding from " + getClass().getName());
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
index 45a8466..55e6141 100644
--- a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -31,7 +31,6 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
-import android.hardware.HardwareBuffer;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -67,8 +66,7 @@
 
             Bitmap wrappedBuffer = null;
             if (contextImage != null) {
-                wrappedBuffer = Bitmap.wrapHardwareBuffer(
-                        HardwareBuffer.createFromGraphicBuffer(contextImage), null);
+                wrappedBuffer = Bitmap.wrapHardwareBuffer(contextImage, null);
             }
 
             mHandler.sendMessage(
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 8ba9a83..e81ce7f 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.StringDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Notification;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -40,6 +41,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class Adjustment implements Parcelable {
     private final String mPackage;
     private final String mKey;
@@ -130,6 +132,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public Adjustment(String pkg, String key, Bundle signals, CharSequence explanation, int user) {
         mPackage = pkg;
         mKey = key;
@@ -212,6 +215,7 @@
 
     /** @hide */
     @SystemApi
+    @TestApi
     public int getUser() {
         return mUser;
     }
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 22104b5..5977baf 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -53,4 +53,5 @@
     void onNotificationDirectReply(String key);
     void onSuggestedReplySent(String key, in CharSequence reply, int source);
     void onActionClicked(String key, in Notification.Action action, int source);
+    void onAllowedAdjustmentsChanged();
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index b81725d..cafeb87 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -65,6 +66,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public abstract class NotificationAssistantService extends NotificationListenerService {
     private static final String TAG = "NotificationAssistants";
 
@@ -218,10 +220,10 @@
     /**
      * Implement this to know when a user has changed which features of
      * their notifications the assistant can modify.
-     * <p> Query {@link NotificationManager#getAllowedAssistantCapabilities()} to see what
+     * <p> Query {@link NotificationManager#getAllowedAssistantAdjustments()} to see what
      * {@link Adjustment adjustments} you are currently allowed to make.</p>
      */
-    public void onCapabilitiesChanged() {
+    public void onAllowedAdjustmentsChanged() {
     }
 
     /**
@@ -357,6 +359,11 @@
             args.argi2 = source;
             mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_INVOKED, args).sendToTarget();
         }
+
+        @Override
+        public void onAllowedAdjustmentsChanged() {
+            mHandler.obtainMessage(MyHandler.MSG_ON_ALLOWED_ADJUSTMENTS_CHANGED).sendToTarget();
+        }
     }
 
     private final class MyHandler extends Handler {
@@ -367,6 +374,7 @@
         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_INVOKED = 7;
+        public static final int MSG_ON_ALLOWED_ADJUSTMENTS_CHANGED = 8;
 
         public MyHandler(Looper looper) {
             super(looper, null, false);
@@ -448,6 +456,10 @@
                     onActionInvoked(key, action, source);
                     break;
                 }
+                case MSG_ON_ALLOWED_ADJUSTMENTS_CHANGED: {
+                    onAllowedAdjustmentsChanged();
+                    break;
+                }
             }
         }
     }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 333868a..3ec21e3 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import android.annotation.CurrentTimeMillisLong;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SdkConstant;
@@ -1399,6 +1400,11 @@
         }
 
         @Override
+        public void onAllowedAdjustmentsChanged() {
+            // no-op in the listener
+        }
+
+        @Override
         public void onNotificationChannelModification(String pkgName, UserHandle user,
                 NotificationChannel channel,
                 @ChannelOrGroupModificationTypes int modificationType) {
@@ -1675,6 +1681,7 @@
          *
          * @return the time of the last alerting behavior, in milliseconds.
          */
+        @CurrentTimeMillisLong
         public long getLastAudiblyAlertedMillis() {
             return mLastAudiblyAlertedMs;
         }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 04046fe..feff9db 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,6 +42,8 @@
             "settings_global_actions_force_grid_enabled";
     public static final String GLOBAL_ACTIONS_PANEL_ENABLED =
             "settings_global_actions_panel_enabled";
+    public static final String PIXEL_WALLPAPER_CATEGORY_SWITCH =
+            "settings_pixel_wallpaper_category_switch";
     public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
 
     private static final Map<String, String> DEFAULT_FLAGS;
@@ -60,6 +62,7 @@
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
         DEFAULT_FLAGS.put(FORCE_GLOBAL_ACTIONS_GRID_ENABLED, "false");
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
+        DEFAULT_FLAGS.put(PIXEL_WALLPAPER_CATEGORY_SWITCH, "false");
         DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "true");
         DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
     }
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
index cd2b6ce..c290dff 100644
--- a/core/java/android/util/proto/ProtoInputStream.java
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -16,8 +16,6 @@
 
 package android.util.proto;
 
-import android.annotation.TestApi;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
@@ -64,7 +62,6 @@
  *
  * @hide
  */
-@TestApi
 public final class ProtoInputStream extends ProtoStream {
 
     public static final int NO_MORE_FIELDS = -1;
diff --git a/core/java/android/util/proto/TEST_MAPPING b/core/java/android/util/proto/TEST_MAPPING
new file mode 100644
index 0000000..cf9f077
--- /dev/null
+++ b/core/java/android/util/proto/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "ProtoInputStreamTests"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 597b34bf..956161a 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -41,9 +41,11 @@
      * with remote animation targets should be relinquished. If {@param moveHomeToTop} is true, then
      * the home activity should be moved to the top. Otherwise, the home activity is hidden and the
      * user is returned to the app.
+     * @param sendUserLeaveHint If set to true, {@link Activity#onUserLeaving} will be sent to the
+     *                          top resumed app, false otherwise.
      */
     @UnsupportedAppUsage
-    void finish(boolean moveHomeToTop);
+    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint);
 
     /**
      * Called by the handler to indicate that the recents animation input consumer should be
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 1383463..a780158 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -153,6 +153,7 @@
             return;
         }
         mVisible = visible;
+        applyHiddenToControl();
         applyLocalVisibilityOverride();
         mController.notifyVisibilityChanged();
     }
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index f9b629c8..1fc7f0e 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -416,23 +416,8 @@
     }
 
     private void initPrecompiledViews() {
-        // Use the device config if enabled, otherwise default to the system property.
-        String usePrecompiledLayout = null;
-        try {
-            usePrecompiledLayout = DeviceConfig.getProperty(
-                    DeviceConfig.NAMESPACE_RUNTIME,
-                    USE_PRECOMPILED_LAYOUT);
-        } catch (Exception e) {
-          // May be caused by permission errors reading the property (i.e. instant apps).
-        }
+        // Precompiled layouts are not supported in this release.
         boolean enabled = false;
-        if (TextUtils.isEmpty(usePrecompiledLayout)) {
-            enabled = SystemProperties.getBoolean(
-                    USE_PRECOMPILED_LAYOUT,
-                    false);
-        } else {
-            enabled = Boolean.parseBoolean(usePrecompiledLayout);
-        }
         initPrecompiledViews(enabled);
     }
 
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ec62e19..b5ad908 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -41,7 +41,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.hardware.HardwareBuffer;
 import android.hardware.display.DisplayedContentSample;
 import android.hardware.display.DisplayedContentSamplingAttributes;
 import android.os.Build;
@@ -439,10 +438,13 @@
     public static class ScreenshotGraphicBuffer {
         private final GraphicBuffer mGraphicBuffer;
         private final ColorSpace mColorSpace;
+        private final boolean mContainsSecureLayers;
 
-        public ScreenshotGraphicBuffer(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
+        public ScreenshotGraphicBuffer(GraphicBuffer graphicBuffer, ColorSpace colorSpace,
+                boolean containsSecureLayers) {
             mGraphicBuffer = graphicBuffer;
             mColorSpace = colorSpace;
+            mContainsSecureLayers = containsSecureLayers;
         }
 
        /**
@@ -453,13 +455,16 @@
         * @param usage Hint indicating how the buffer will be used
         * @param unwrappedNativeObject The native object of GraphicBuffer
         * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
+        * @param containsSecureLayer Indicates whether this graphic buffer contains captured contents
+        *        of secure layers, in which case the screenshot should not be persisted.
         */
         private static ScreenshotGraphicBuffer createFromNative(int width, int height, int format,
-                int usage, long unwrappedNativeObject, int namedColorSpace) {
+                int usage, long unwrappedNativeObject, int namedColorSpace,
+                boolean containsSecureLayers) {
             GraphicBuffer graphicBuffer = GraphicBuffer.createFromExisting(width, height, format,
                     usage, unwrappedNativeObject);
             ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
-            return new ScreenshotGraphicBuffer(graphicBuffer, colorSpace);
+            return new ScreenshotGraphicBuffer(graphicBuffer, colorSpace, containsSecureLayers);
         }
 
         public ColorSpace getColorSpace() {
@@ -469,6 +474,10 @@
         public GraphicBuffer getGraphicBuffer() {
             return mGraphicBuffer;
         }
+
+        public boolean containsSecureLayers() {
+            return mContainsSecureLayers;
+        }
     }
 
     /**
@@ -1907,9 +1916,7 @@
             Log.w(TAG, "Failed to take screenshot");
             return null;
         }
-        return Bitmap.wrapHardwareBuffer(
-                HardwareBuffer.createFromGraphicBuffer(buffer.getGraphicBuffer()),
-                buffer.getColorSpace());
+        return Bitmap.wrapHardwareBuffer(buffer.getGraphicBuffer(), buffer.getColorSpace());
     }
 
     /**
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 81e9c13..9e914d4 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -87,6 +87,12 @@
 
     /**
      * Defines the duration in milliseconds a user needs to hold down the
+     * appropriate buttons (power + volume down) to trigger the screenshot chord.
+     */
+    private static final int SCREENSHOT_CHORD_KEY_TIMEOUT = 500;
+
+    /**
+     * Defines the duration in milliseconds a user needs to hold down the
      * appropriate button to bring up the accessibility shortcut for the first time
      */
     private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000;
@@ -316,6 +322,7 @@
     private final float mVerticalScrollFactor;
     private final float mHorizontalScrollFactor;
     private final boolean mShowMenuShortcutsWhenKeyboardPresent;
+    private final long mScreenshotChordKeyTimeout;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768915)
     private boolean sHasPermanentMenuKey;
@@ -353,6 +360,7 @@
         mHorizontalScrollFactor = HORIZONTAL_SCROLL_FACTOR;
         mVerticalScrollFactor = VERTICAL_SCROLL_FACTOR;
         mShowMenuShortcutsWhenKeyboardPresent = false;
+        mScreenshotChordKeyTimeout = SCREENSHOT_CHORD_KEY_TIMEOUT;
 
         // Getter throws if mConstructedWithContext is false so doesn't matter what
         // this value is.
@@ -457,6 +465,9 @@
 
         mMinScalingSpan = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.config_minScalingSpan);
+
+        mScreenshotChordKeyTimeout = res.getInteger(
+                com.android.internal.R.integer.config_screenshotChordKeyTimeout);
     }
 
     /**
@@ -890,6 +901,18 @@
     }
 
     /**
+     * The amount of time a user needs to press the relevant keys to trigger
+     * the screenshot chord.
+     *
+     * @return how long a user needs to press the relevant keys to trigger
+     *   the screenshot chord.
+     * @hide
+     */
+    public long getScreenshotChordKeyTimeout() {
+        return mScreenshotChordKeyTimeout;
+    }
+
+    /**
      * The amount of time a user needs to press the relevant keys to activate the accessibility
      * shortcut.
      *
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 2896bd0..c50a3aa 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -932,7 +932,8 @@
      * @param listener listener to add
      * @see View#setSystemGestureExclusionRects(List)
      */
-    public void addOnSystemGestureExclusionRectsChangedListener(Consumer<List<Rect>> listener) {
+    public void addOnSystemGestureExclusionRectsChangedListener(
+            @NonNull Consumer<List<Rect>> listener) {
         checkIsAlive();
         if (mGestureExclusionListeners == null) {
             mGestureExclusionListeners = new CopyOnWriteArray<>();
@@ -945,7 +946,8 @@
      * @see #addOnSystemGestureExclusionRectsChangedListener(Consumer)
      * @see View#setSystemGestureExclusionRects(List)
      */
-    public void removeOnSystemGestureExclusionRectsChangedListener(Consumer<List<Rect>> listener) {
+    public void removeOnSystemGestureExclusionRectsChangedListener(
+            @NonNull Consumer<List<Rect>> listener) {
         checkIsAlive();
         if (mGestureExclusionListeners == null) {
             return;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 3544a87..a9463e9 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -2329,6 +2329,70 @@
         return 0;
     }
 
+    /**
+     * Sets whether the system should ensure that the status bar has enough
+     * contrast when a fully transparent background is requested.
+     *
+     * <p>If set to this value, the system will determine whether a scrim is necessary
+     * to ensure that the status bar has enough contrast with the contents of
+     * this app, and set an appropriate effective bar background color accordingly.
+     *
+     * <p>When the status bar color has a non-zero alpha value, the value of this
+     * property has no effect.
+     *
+     * @see android.R.attr#ensureStatusBarContrastWhenTransparent
+     * @hide pending API
+     */
+    public void setEnsureStatusBarContrastWhenTransparent(boolean ensureContrast) {
+    }
+
+    /**
+     * Returns whether the system is ensuring that the status bar has enough contrast when a
+     * fully transparent background is requested.
+     *
+     * <p>When the status bar color has a non-zero alpha value, the value of this
+     * property has no effect.
+     *
+     * @see android.R.attr#ensureStatusBarContrastWhenTransparent
+     * @return true, if the system is ensuring contrast, false otherwise.
+     * @hide pending API
+     */
+    public boolean isEnsureStatusBarContrastWhenTransparent() {
+        return false;
+    }
+
+    /**
+     * Sets whether the system should ensure that the navigation bar has enough
+     * contrast when a fully transparent background is requested.
+     *
+     * <p>If set to this value, the system will determine whether a scrim is necessary
+     * to ensure that the navigation bar has enough contrast with the contents of
+     * this app, and set an appropriate effective bar background color accordingly.
+     *
+     * <p>When the navigation bar color has a non-zero alpha value, the value of this
+     * property has no effect.
+     *
+     * @see android.R.attr#ensureNavigationBarContrastWhenTransparent
+     * @hide pending API
+     */
+    public void setEnsureNavigationBarContrastWhenTransparent(boolean ensureContrast) {
+    }
+
+    /**
+     * Returns whether the system is ensuring that the navigation bar has enough contrast when a
+     * fully transparent background is requested.
+     *
+     * <p>When the navigation bar color has a non-zero alpha value, the value of this
+     * property has no effect.
+     *
+     * @return true, if the system is ensuring contrast, false otherwise.
+     * @see android.R.attr#ensureNavigationBarContrastWhenTransparent
+     * @hide pending API
+     */
+    public boolean isEnsureNavigationBarContrastWhenTransparent() {
+        return false;
+    }
+
     /** @hide */
     public void setTheme(int resId) {
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java
index cf171d7..6f9d4d3 100644
--- a/core/java/android/view/contentcapture/ContentCaptureCondition.java
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java
@@ -54,7 +54,9 @@
      *
      * @param locusId id of the condition, as defined by
      * {@link ContentCaptureContext#getLocusId()}.
-     * @param flags either {@link ContentCaptureCondition#FLAG_IS_REGEX} or {@code 0}.
+     * @param flags either {@link ContentCaptureCondition#FLAG_IS_REGEX} (to use a regular
+     * expression match) or {@code 0} (in which case the {@code LocusId} must be an exact match of
+     * the {@code LocusId} used in the {@link ContentCaptureContext}).
      */
     public ContentCaptureCondition(@NonNull LocusId locusId, @Flags int flags) {
         this.mLocusId = Preconditions.checkNotNull(locusId);
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index f2d878a..6070b53 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -200,13 +200,11 @@
     /**
      * Returns the extended data related to this conversation action.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     /** Builder class to construct {@link ConversationAction}. */
@@ -268,7 +266,7 @@
                     mAction,
                     mTextReply,
                     mScore,
-                    mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+                    mExtras == null ? Bundle.EMPTY : mExtras);
         }
     }
 }
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index dc75212..b408129 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -214,13 +214,11 @@
         /**
          * Returns the extended data related to this conversation action.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /** Builder class to construct a {@link Message} */
@@ -277,7 +275,7 @@
                         mAuthor,
                         mReferenceTime,
                         mText == null ? null : new SpannedString(mText),
-                        mExtras == null ? new Bundle() : mExtras.deepCopy());
+                        mExtras == null ? Bundle.EMPTY : mExtras);
             }
         }
     }
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 9ede8fb..6321051 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -265,13 +265,11 @@
     /**
      * Returns the extended data.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     @Override
@@ -523,7 +521,7 @@
         }
 
         private Bundle buildExtras(EntityConfidence entityConfidence) {
-            final Bundle extras = mExtras == null ? new Bundle() : mExtras.deepCopy();
+            final Bundle extras = mExtras == null ? new Bundle() : mExtras;
             if (mActionIntents.stream().anyMatch(Objects::nonNull)) {
                 ExtrasUtils.putActionsIntents(extras, mActionIntents);
             }
@@ -635,13 +633,11 @@
         /**
          * Returns the extended data.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /**
@@ -717,7 +713,7 @@
             public Request build() {
                 return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
                         mDefaultLocales, mReferenceTime,
-                        mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+                        mExtras == null ? Bundle.EMPTY : mExtras);
             }
         }
 
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index eaf4d7f..6c75ffb 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -113,12 +113,11 @@
      * Returns a bundle containing non-structured extra information about this result. What is
      * returned in the extras is specific to the {@link TextClassifier} implementation.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should prefer
-     * to hold a reference to the returned bundle rather than frequently calling this method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mBundle.deepCopy();
+        return mBundle;
     }
 
     @Override
@@ -199,7 +198,7 @@
          */
         @NonNull
         public TextLanguage build() {
-            mBundle = mBundle == null ? new Bundle() : mBundle.deepCopy();
+            mBundle = mBundle == null ? Bundle.EMPTY : mBundle;
             return new TextLanguage(
                     mId,
                     new EntityConfidence(mEntityConfidenceMap),
@@ -263,13 +262,11 @@
         /**
          * Returns a bundle containing non-structured extra information about this request.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtra.deepCopy();
+            return mExtra;
         }
 
         @Override
@@ -327,8 +324,7 @@
              */
             @NonNull
             public Request build() {
-                mBundle = mBundle == null ? new Bundle() : mBundle.deepCopy();
-                return new Request(mText.toString(), mBundle);
+                return new Request(mText.toString(), mBundle == null ? Bundle.EMPTY : mBundle);
             }
         }
     }
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index cde27a0..66a72f9 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -125,13 +125,11 @@
     /**
      * Returns the extended data.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     /**
@@ -413,13 +411,11 @@
         /**
          * Returns the extended data.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /**
@@ -497,7 +493,7 @@
                 return new Request(
                         mText, mDefaultLocales, mEntityConfig,
                         mLegacyFallback,
-                        mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+                        mExtras == null ? Bundle.EMPTY : mExtras);
             }
         }
 
@@ -706,7 +702,7 @@
         @NonNull
         public TextLinks build() {
             return new TextLinks(mFullText, mLinks,
-                    mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+                    mExtras == null ? Bundle.EMPTY : mExtras);
         }
     }
 }
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 5298939..75c27bd 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -112,13 +112,11 @@
     /**
      * Returns the extended data.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     @Override
@@ -197,7 +195,7 @@
         public TextSelection build() {
             return new TextSelection(
                     mStartIndex, mEndIndex, mEntityConfidence, mId,
-                    mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+                    mExtras == null ? Bundle.EMPTY : mExtras);
         }
     }
 
@@ -296,13 +294,11 @@
         /**
          * Returns the extended data.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /**
@@ -382,7 +378,7 @@
             public Request build() {
                 return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
                         mDefaultLocales, mDarkLaunchAllowed,
-                        mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+                        mExtras == null ? Bundle.EMPTY : mExtras);
             }
         }
 
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 62f54b9..2bfbe4b 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -17,7 +17,6 @@
 package android.webkit;
 
 import android.content.pm.PackageInfo;
-import android.os.AsyncTask;
 import android.os.Build;
 import android.os.ChildZygoteProcess;
 import android.os.Process;
@@ -81,17 +80,9 @@
         synchronized (sLock) {
             sMultiprocessEnabled = enabled;
 
-            // When toggling between multi-process being on/off, start or stop the
-            // zygote. If it is enabled and the zygote is not yet started, launch it.
-            // Otherwise, kill it. The name may be null if the package information has
-            // not yet been resolved.
-            if (enabled) {
-                // Run on a background thread as this waits for the zygote to start and we don't
-                // want to block the caller on this. It's okay if this is delayed as anyone trying
-                // to use the zygote will call it first anyway.
-                AsyncTask.THREAD_POOL_EXECUTOR.execute(WebViewZygote::getProcess);
-            } else {
-                // No need to run this in the background, it's very brief.
+            // When multi-process is disabled, kill the zygote. When it is enabled,
+            // the zygote will be started when it is first needed in getProcess().
+            if (!enabled) {
                 stopZygoteLocked();
             }
         }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 94be25f..b51f808 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -43,6 +43,7 @@
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.LabeledIntent;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
@@ -117,12 +118,18 @@
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
+/**
+ * The Chooser Activity handles intent resolution specifically for sharing intents -
+ * for example, those generated by @see android.content.Intent#createChooser(Intent, CharSequence).
+ *
+ */
 public class ChooserActivity extends ResolverActivity {
     private static final String TAG = "ChooserActivity";
 
@@ -200,6 +207,8 @@
     /** {@link ChooserActivity#getBaseScore} */
     private static final float SHORTCUT_TARGET_SCORE_BOOST = 10.f;
     private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment";
+    // TODO: Update to handle landscape instead of using static value
+    private static final int MAX_RANKED_TARGETS = 4;
 
     private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
 
@@ -216,6 +225,7 @@
 
     private boolean mListViewDataChanged = false;
 
+
     @Retention(SOURCE)
     @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT})
     private @interface ContentPreviewType {
@@ -228,6 +238,9 @@
     private static final int CONTENT_PREVIEW_TEXT = 3;
     protected MetricsLogger mMetricsLogger;
 
+    // Sorted list of DisplayResolveInfos for the alphabetical app section.
+    private List<ResolverActivity.DisplayResolveInfo> mSortedList = new ArrayList<>();
+
     private final Handler mChooserHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -935,8 +948,11 @@
         // Note that this is only safe because the Intent handled by the ChooserActivity is
         // guaranteed to contain no extras unknown to the local ClassLoader. That is why this
         // method can not be replaced in the ResolverActivity whole hog.
-        return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE,
-                super.shouldAutoLaunchSingleChoice(target));
+        if (!super.shouldAutoLaunchSingleChoice(target)) {
+            return false;
+        }
+
+        return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true);
     }
 
     @Override
@@ -961,10 +977,6 @@
 
     @Override
     protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
-        if (target instanceof NotSelectableTargetInfo) {
-            return false;
-        }
-
         if (mRefinementIntentSender != null) {
             final Intent fillIn = new Intent();
             final List<Intent> sourceIntents = target.getAllSourceIntents();
@@ -997,6 +1009,11 @@
 
     @Override
     public void startSelected(int which, boolean always, boolean filtered) {
+        TargetInfo targetInfo = mChooserListAdapter.targetInfoForPosition(which, filtered);
+        if (targetInfo != null && targetInfo instanceof NotSelectableTargetInfo) {
+            return;
+        }
+
         final long selectionCost = System.currentTimeMillis() - mChooserShownTime;
         super.startSelected(which, always, filtered);
 
@@ -1030,6 +1047,12 @@
                     value -= mChooserListAdapter.getCallerTargetCount()
                             + mChooserListAdapter.getSelectableServiceTargetCount();
                     break;
+                case ChooserListAdapter.TARGET_STANDARD_AZ:
+                    // A-Z targets are unranked standard targets; we use -1 to mark that they
+                    // are from the alphabetical pool.
+                    value = -1;
+                    cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
+                    break;
             }
 
             if (cat != 0) {
@@ -1405,6 +1428,30 @@
         }
     }
 
+    private void updateAlphabeticalList() {
+        if (getDisplayList().size() > MAX_RANKED_TARGETS) {
+            mSortedList.clear();
+            mSortedList.addAll(getDisplayList());
+            Collections.sort(mSortedList, new AzInfoComparator(ChooserActivity.this));
+        }
+    }
+
+    /**
+     * Sort intents alphabetically based on display label.
+     */
+    class AzInfoComparator implements Comparator<ResolverActivity.DisplayResolveInfo> {
+        Collator mCollator;
+        AzInfoComparator(Context context) {
+            mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+        }
+
+        @Override
+        public int compare(ResolverActivity.DisplayResolveInfo lhsp,
+                ResolverActivity.DisplayResolveInfo rhsp) {
+            return mCollator.compare(lhsp.getDisplayLabel(), rhsp.getDisplayLabel());
+        }
+    }
+
     protected MetricsLogger getMetricsLogger() {
         if (mMetricsLogger == null) {
             mMetricsLogger = new MetricsLogger();
@@ -1451,7 +1498,8 @@
                 mPm,
                 getTargetIntent(),
                 getReferrerPackageName(),
-                mLaunchedFromUid);
+                mLaunchedFromUid
+                );
     }
 
     @VisibleForTesting
@@ -1527,6 +1575,10 @@
         public ChooserTarget getChooserTarget() {
             return null;
         }
+
+        public boolean isSuspended() {
+            return false;
+        }
     }
 
     final class PlaceHolderTargetInfo extends NotSelectableTargetInfo {
@@ -1552,6 +1604,7 @@
         private final Intent mFillInIntent;
         private final int mFillInFlags;
         private final float mModifiedScore;
+        private boolean mIsSuspended;
 
         SelectableTargetInfo(DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget,
                 float modifiedScore) {
@@ -1580,6 +1633,8 @@
 
             mFillInIntent = null;
             mFillInFlags = 0;
+            ApplicationInfo ai = sourceInfo.getResolveInfo().activityInfo.applicationInfo;
+            mIsSuspended = (ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
         }
 
         private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) {
@@ -1594,6 +1649,10 @@
             mModifiedScore = other.mModifiedScore;
         }
 
+        public boolean isSuspended() {
+            return mIsSuspended;
+        }
+
         /**
          * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip
          * the call to LauncherApps#getShortcuts(ShortcutQuery).
@@ -1789,7 +1848,7 @@
                 int offset = 0;
                 int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
                         + mChooserRowAdapter.getServiceTargetRowCount()
-                        + mChooserRowAdapter.getCallerTargetRowCount();
+                        + mChooserRowAdapter.getCallerAndRankedTargetRowCount();
 
                 // then this is most likely not a SEND_* action, so check
                 // the app target count
@@ -1833,6 +1892,7 @@
         public static final int TARGET_CALLER = 0;
         public static final int TARGET_SERVICE = 1;
         public static final int TARGET_STANDARD = 2;
+        public static final int TARGET_STANDARD_AZ = 3;
 
         private static final int MAX_SUGGESTED_APP_TARGETS = 4;
         private static final int MAX_TARGETS_PER_SERVICE = 2;
@@ -1843,8 +1903,6 @@
         private ChooserTargetInfo mPlaceHolderTargetInfo = new PlaceHolderTargetInfo();
         private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
         private final List<TargetInfo> mCallerTargets = new ArrayList<>();
-        private boolean mShowServiceTargets;
-
         private boolean mTargetsNeedPruning = false;
 
         private final BaseChooserTargetComparator mBaseTargetComparator
@@ -1974,6 +2032,7 @@
 
                 queryTargetServices(this);
             }
+            updateAlphabeticalList();
         }
 
         @Override
@@ -1983,13 +2042,17 @@
 
         @Override
         public int getCount() {
-            return super.getCount() + getSelectableServiceTargetCount() + getCallerTargetCount();
+            return getRankedTargetCount() + getAlphaTargetCount()
+                    + getSelectableServiceTargetCount() + getCallerTargetCount();
         }
 
         @Override
         public int getUnfilteredCount() {
-            return super.getUnfilteredCount() + getSelectableServiceTargetCount()
-                    + getCallerTargetCount();
+            int appTargets = super.getUnfilteredCount();
+            if (appTargets > MAX_RANKED_TARGETS) {
+                appTargets = appTargets + MAX_RANKED_TARGETS;
+            }
+            return appTargets + getSelectableServiceTargetCount() + getCallerTargetCount();
         }
 
         public int getCallerTargetCount() {
@@ -2017,10 +2080,17 @@
             return 0;
         }
 
-        public int getStandardTargetCount() {
-            return super.getCount();
+        int getAlphaTargetCount() {
+            int standardCount = super.getCount();
+            return standardCount > MAX_RANKED_TARGETS ? standardCount : 0;
         }
 
+        int getRankedTargetCount() {
+            int spacesAvailable = MAX_RANKED_TARGETS - getCallerTargetCount();
+            return Math.min(spacesAvailable, super.getCount());
+        }
+
+
         public int getPositionTargetType(int position) {
             int offset = 0;
 
@@ -2036,10 +2106,16 @@
             }
             offset += callerTargetCount;
 
-            final int standardTargetCount = super.getCount();
-            if (position - offset < standardTargetCount) {
+            final int rankedTargetCount = getRankedTargetCount();
+            if (position - offset < rankedTargetCount) {
                 return TARGET_STANDARD;
             }
+            offset += rankedTargetCount;
+
+            final int standardTargetCount = getAlphaTargetCount();
+            if (position - offset < standardTargetCount) {
+                return TARGET_STANDARD_AZ;
+            }
 
             return TARGET_BAD;
         }
@@ -2049,10 +2125,17 @@
             return targetInfoForPosition(position, true);
         }
 
+
+        /**
+         * Find target info for a given position.
+         * Since ChooserActivity displays several sections of content, determine which
+         * section provides this item.
+         */
         @Override
         public TargetInfo targetInfoForPosition(int position, boolean filtered) {
             int offset = 0;
 
+            // Direct share targets
             final int serviceTargetCount = filtered ? getServiceTargetCount() :
                                                getSelectableServiceTargetCount();
             if (position < serviceTargetCount) {
@@ -2060,16 +2143,30 @@
             }
             offset += serviceTargetCount;
 
+            // Targets provided by calling app
             final int callerTargetCount = getCallerTargetCount();
             if (position - offset < callerTargetCount) {
                 return mCallerTargets.get(position - offset);
             }
             offset += callerTargetCount;
 
-            return filtered ? super.getItem(position - offset)
-                    : getDisplayResolveInfo(position - offset);
+            // Ranked standard app targets
+            final int rankedTargetCount = getRankedTargetCount();
+            if (position - offset < rankedTargetCount) {
+                return filtered ? super.getItem(position - offset)
+                        : getDisplayResolveInfo(position - offset);
+            }
+            offset += rankedTargetCount;
+
+            // Alphabetical complete app target list.
+            if (position - offset < getAlphaTargetCount() && !mSortedList.isEmpty()) {
+                return mSortedList.get(position - offset);
+            }
+
+            return null;
         }
 
+
         /**
          * Evaluate targets for inclusion in the direct share area. May not be included
          * if score is too low.
@@ -2100,6 +2197,9 @@
 
             final float baseScore = getBaseScore(origTarget, isShortcutResult);
             Collections.sort(targets, mBaseTargetComparator);
+
+
+
             float lastScore = 0;
             boolean shouldNotify = false;
             for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) {
@@ -2204,6 +2304,7 @@
         }
     }
 
+
     private boolean isSendAction(Intent targetIntent) {
         if (targetIntent == null) {
             return false;
@@ -2292,12 +2393,13 @@
 
         @Override
         public int getCount() {
+
             return (int) (
                     getContentPreviewRowCount()
-                            + getCallerTargetRowCount()
                             + getServiceTargetRowCount()
+                            + getCallerAndRankedTargetRowCount()
                             + Math.ceil(
-                            (float) mChooserListAdapter.getStandardTargetCount()
+                            (float) mChooserListAdapter.getAlphaTargetCount()
                                     / getMaxTargetsPerRow())
             );
         }
@@ -2314,9 +2416,10 @@
             return 1;
         }
 
-        public int getCallerTargetRowCount() {
+        public int getCallerAndRankedTargetRowCount() {
             return (int) Math.ceil(
-                    (float) mChooserListAdapter.getCallerTargetCount() / getMaxTargetsPerRow());
+                    ((float) mChooserListAdapter.getCallerTargetCount()
+                            + mChooserListAdapter.getRankedTargetCount()) / getMaxTargetsPerRow());
         }
 
         // There can be at most one row in the listview, that is internally
@@ -2442,8 +2545,8 @@
 
             if (isDirectShare) {
                 DirectShareViewHolder dsvh = (DirectShareViewHolder) holder;
-                setViewHeight(dsvh.getRow(0), holder.getMeasuredRowHeight());
-                setViewHeight(dsvh.getRow(1), holder.getMeasuredRowHeight());
+                setViewHeight(dsvh.getRow(0), dsvh.getMinRowHeight());
+                setViewHeight(dsvh.getRow(1), dsvh.getMinRowHeight());
             }
 
             viewGroup.setTag(holder);
@@ -2498,10 +2601,8 @@
 
             if (startType != lastStartType || rowPosition == getContentPreviewRowCount()) {
                 row.setBackground(mChooserRowLayer);
-                setVertPadding(row, 0, 0);
             } else {
                 row.setBackground(null);
-                setVertPadding(row, 0, 0);
             }
 
             int columnCount = holder.getColumnCount();
@@ -2548,10 +2649,6 @@
             }
         }
 
-        private void setVertPadding(ViewGroup row, int top, int bottom) {
-            row.setPadding(row.getPaddingLeft(), top, row.getPaddingRight(), bottom);
-        }
-
         int getFirstRowPosition(int row) {
             row -= getContentPreviewRowCount();
 
@@ -2731,6 +2828,10 @@
             return mDirectShareCurrHeight;
         }
 
+        public int getMinRowHeight() {
+            return mDirectShareMinHeight;
+        }
+
         public void setViewVisibility(int i, int visibility) {
             final View v = getView(i);
             if (visibility == View.VISIBLE) {
@@ -2753,15 +2854,20 @@
         }
 
         public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) {
-            if (mHideDirectShareExpansion) {
-                return;
-            }
+            // only exit early if fully collapsed, otherwise onListRebuilt() with shifting
+            // targets can lock us into an expanded mode
+            boolean notExpanded = mDirectShareCurrHeight == mDirectShareMinHeight;
+            if (notExpanded) {
+                if (mHideDirectShareExpansion) {
+                    return;
+                }
 
-            // only expand if we have more than maxTargetsPerRow, and delay that decision
-            // until they start to scroll
-            if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
-                mHideDirectShareExpansion = true;
-                return;
+                // only expand if we have more than maxTargetsPerRow, and delay that decision
+                // until they start to scroll
+                if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
+                    mHideDirectShareExpansion = true;
+                    return;
+                }
             }
 
             int yDiff = (int) ((oldy - y) * DIRECT_SHARE_EXPANSION_RATE);
@@ -2961,6 +3067,7 @@
         private int mRadius = 0;
         private Path mPath = new Path();
         private Paint mOverlayPaint = new Paint(0);
+        private Paint mRoundRectPaint = new Paint(0);
         private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         private String mExtraImageCount = null;
 
@@ -2984,6 +3091,11 @@
             mOverlayPaint.setColor(0x99000000);
             mOverlayPaint.setStyle(Paint.Style.FILL);
 
+            mRoundRectPaint.setColor(context.getResources().getColor(R.color.chooser_row_divider));
+            mRoundRectPaint.setStyle(Paint.Style.STROKE);
+            mRoundRectPaint.setStrokeWidth(context.getResources()
+                    .getDimensionPixelSize(R.dimen.chooser_preview_image_border));
+
             mTextPaint.setColor(Color.WHITE);
             mTextPaint.setTextSize(context.getResources()
                     .getDimensionPixelSize(R.dimen.chooser_preview_image_font_size));
@@ -2993,8 +3105,8 @@
         private void updatePath(int width, int height) {
             mPath.reset();
 
-            int imageWidth = width - getPaddingRight();
-            int imageHeight = height - getPaddingBottom();
+            int imageWidth = width - getPaddingRight() - getPaddingLeft();
+            int imageHeight = height - getPaddingBottom() - getPaddingTop();
             mPath.addRoundRect(getPaddingLeft(), getPaddingTop(), imageWidth, imageHeight, mRadius,
                     mRadius, Path.Direction.CW);
         }
@@ -3026,7 +3138,6 @@
             updatePath(width, height);
         }
 
-
         @Override
         protected void onDraw(Canvas canvas) {
             if (mRadius != 0) {
@@ -3035,8 +3146,12 @@
 
             super.onDraw(canvas);
 
+            int x = getPaddingLeft();
+            int y = getPaddingRight();
+            int width = getWidth() - getPaddingRight() - getPaddingLeft();
+            int height = getHeight() - getPaddingBottom() - getPaddingTop();
             if (mExtraImageCount != null) {
-                canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mOverlayPaint);
+                canvas.drawRect(x, y, width, height, mOverlayPaint);
 
                 int xPos = canvas.getWidth() / 2;
                 int yPos = (int) ((canvas.getHeight() / 2.0f)
@@ -3044,6 +3159,8 @@
 
                 canvas.drawText(mExtraImageCount, xPos, yPos, mTextPaint);
             }
+
+            canvas.drawRoundRect(x, y, width, height, mRadius, mRadius, mRoundRectPaint);
         }
     }
 }
diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
index 7735d84..0152387 100644
--- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -16,11 +16,11 @@
 
 package com.android.internal.app;
 
-import com.android.internal.R;
-
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.app.IApplicationThread;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
@@ -29,13 +29,14 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.View;
-import android.view.Window;
 import android.view.View.OnClickListener;
+import android.view.Window;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.R;
+
 /**
  * This activity is displayed when the system attempts to start an Intent for
  * which there is more than one matching activity, allowing the user to decide
@@ -127,7 +128,10 @@
     private OnClickListener mSwitchOldListener = new OnClickListener() {
         public void onClick(View v) {
             try {
-                ActivityTaskManager.getService().moveTaskToFront(mCurTask, 0, null);
+                ActivityThread thread = ActivityThread.currentActivityThread();
+                IApplicationThread appThread = thread.getApplicationThread();
+                ActivityTaskManager.getService().moveTaskToFront(appThread, getPackageName(),
+                        mCurTask, 0, null);
             } catch (RemoteException e) {
             }
             finish();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f671a75..ad1e767 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -44,6 +44,8 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -132,6 +134,8 @@
 
     private boolean mRegistered;
 
+    private ColorMatrixColorFilter mSuspendedMatrixColorFilter;
+
     /** See {@link #setRetainInOnStop}. */
     private boolean mRetainInOnStop;
 
@@ -350,6 +354,8 @@
             bindProfileView();
         }
 
+        initSuspendedColorMatrix();
+
         if (isVoiceInteraction()) {
             onSetupVoiceInteraction();
         }
@@ -367,6 +373,25 @@
         mAdapter.handlePackagesChanged();
     }
 
+    private void initSuspendedColorMatrix() {
+        int grayValue = 127;
+        float scale = 0.5f; // half bright
+
+        ColorMatrix tempBrightnessMatrix = new ColorMatrix();
+        float[] mat = tempBrightnessMatrix.getArray();
+        mat[0] = scale;
+        mat[6] = scale;
+        mat[12] = scale;
+        mat[4] = grayValue;
+        mat[9] = grayValue;
+        mat[14] = grayValue;
+
+        ColorMatrix matrix = new ColorMatrix();
+        matrix.setSaturation(0.0f);
+        matrix.preConcat(tempBrightnessMatrix);
+        mSuspendedMatrixColorFilter = new ColorMatrixColorFilter(matrix);
+    }
+
     /**
      * Perform any initialization needed for voice interaction.
      */
@@ -1019,7 +1044,14 @@
 
         if (target != null) {
             safelyStartActivity(target);
+
+            // Rely on the ActivityManager to pop up a dialog regarding app suspension
+            // and return false
+            if (target.isSuspended()) {
+                return false;
+            }
         }
+
         return true;
     }
 
@@ -1106,7 +1138,7 @@
     }
 
     public boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
-        return true;
+        return !target.isSuspended();
     }
 
     public void showTargetDetails(ResolveInfo ri) {
@@ -1326,6 +1358,7 @@
         private final CharSequence mExtendedInfo;
         private final Intent mResolvedIntent;
         private final List<Intent> mSourceIntents = new ArrayList<>();
+        private boolean mIsSuspended;
 
         public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
                 CharSequence pInfo, Intent pOrigIntent) {
@@ -1341,6 +1374,8 @@
             final ActivityInfo ai = mResolveInfo.activityInfo;
             intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
 
+            mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+
             mResolvedIntent = intent;
         }
 
@@ -1410,7 +1445,6 @@
 
         @Override
         public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
-
             if (mEnableChooserDelegate) {
                 return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
             } else {
@@ -1424,6 +1458,14 @@
             activity.startActivityAsUser(mResolvedIntent, options, user);
             return false;
         }
+
+        public boolean isSuspended() {
+            return mIsSuspended;
+        }
+    }
+
+    List<DisplayResolveInfo> getDisplayList() {
+        return mAdapter.mDisplayList;
     }
 
     /**
@@ -1515,6 +1557,11 @@
          * @return the list of supported source intents deduped against this single target
          */
         List<Intent> getAllSourceIntents();
+
+        /**
+          * @return true if this target can be selected by the user
+          */
+        boolean isSuspended();
     }
 
     public class ResolveListAdapter extends BaseAdapter {
@@ -1523,12 +1570,12 @@
         private final List<ResolveInfo> mBaseResolveList;
         protected ResolveInfo mLastChosen;
         private DisplayResolveInfo mOtherProfile;
-        private boolean mHasExtendedInfo;
         private ResolverListController mResolverListController;
         private int mPlaceholderCount;
 
         protected final LayoutInflater mInflater;
 
+        // This one is the list that the Adapter will actually present.
         List<DisplayResolveInfo> mDisplayList;
         List<ResolvedComponentInfo> mUnfilteredResolveList;
 
@@ -1709,6 +1756,7 @@
             }
         }
 
+
         private void processSortedList(List<ResolvedComponentInfo> sortedComponents) {
             int N;
             if (sortedComponents != null && (N = sortedComponents.size()) != 0) {
@@ -1746,6 +1794,7 @@
                     }
                 }
 
+
                 for (ResolvedComponentInfo rci : sortedComponents) {
                     final ResolveInfo ri = rci.getResolveInfoAt(0);
                     if (ri != null) {
@@ -1755,9 +1804,12 @@
                 }
             }
 
+
             postListReadyRunnable();
         }
 
+
+
         /**
          * Some necessary methods for creating the list are initiated in onCreate and will also
          * determine the layout known. We therefore can't update the UI inline and post to the
@@ -1891,19 +1943,6 @@
             return position;
         }
 
-        public boolean hasExtendedInfo() {
-            return mHasExtendedInfo;
-        }
-
-        public boolean hasResolvedTarget(ResolveInfo info) {
-            for (int i = 0, N = mDisplayList.size(); i < N; i++) {
-                if (resolveInfoMatch(info, mDisplayList.get(i).getResolveInfo())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
         public int getDisplayResolveInfoCount() {
             return mDisplayList.size();
         }
@@ -1960,6 +1999,12 @@
                 holder.text2.setText(subLabel);
             }
 
+            if (info.isSuspended()) {
+                holder.icon.setColorFilter(mSuspendedMatrixColorFilter);
+            } else {
+                holder.icon.setColorFilter(null);
+            }
+
             if (info instanceof DisplayResolveInfo
                     && !((DisplayResolveInfo) info).hasDisplayIcon()) {
                 new LoadIconTask((DisplayResolveInfo) info, holder.icon).execute();
@@ -1969,6 +2014,7 @@
         }
     }
 
+
     @VisibleForTesting
     public static final class ResolvedComponentInfo {
         public final ComponentName name;
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 156baf0..a3cfa87 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -25,7 +25,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.RemoteException;
@@ -153,11 +152,6 @@
     }
 
     // Filter out any activities that the launched uid does not have permission for.
-    //
-    // Also filter out those that are suspended because they couldn't be started. We don't do this
-    // when we have an explicit list of resolved activities, because that only happens when
-    // we are being subclassed, so we can safely launch whatever they gave us.
-    //
     // To preserve the inputList, optionally will return the original list if any modification has
     // been made.
     @VisibleForTesting
@@ -171,9 +165,8 @@
             int granted = ActivityManager.checkComponentPermission(
                     ai.permission, mLaunchedFromUid,
                     ai.applicationInfo.uid, ai.exported);
-            boolean suspended = (ai.applicationInfo.flags
-                    & ApplicationInfo.FLAG_SUSPENDED) != 0;
-            if (granted != PackageManager.PERMISSION_GRANTED || suspended
+
+            if (granted != PackageManager.PERMISSION_GRANTED
                     || isComponentFiltered(ai.getComponentName())) {
                 // Access not allowed! We're about to filter an item,
                 // so modify the unfiltered version if it hasn't already been modified.
@@ -253,6 +246,7 @@
                 isComputed = true;
             }
             Collections.sort(inputList, mResolverComparator);
+
             long afterRank = System.currentTimeMillis();
             if (DEBUG) {
                 Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
@@ -262,6 +256,7 @@
         }
     }
 
+
     private static boolean isSameResolvedComponent(ResolveInfo a,
             ResolverActivity.ResolvedComponentInfo b) {
         final ActivityInfo ai = a.activityInfo;
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index b26efc0..2f9136a 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -78,8 +78,8 @@
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
-        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_TOP
+        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
diff --git a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
deleted file mode 100644
index bf151c3..0000000
--- a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
+++ /dev/null
@@ -1,228 +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.internal.colorextraction.drawable;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.RadialGradient;
-import android.graphics.Rect;
-import android.graphics.Shader;
-import android.graphics.Xfermode;
-import android.graphics.drawable.Drawable;
-import android.view.animation.DecelerateInterpolator;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.graphics.ColorUtils;
-
-/**
- * Draws a gradient based on a Palette
- */
-public class GradientDrawable extends Drawable {
-    private static final String TAG = "GradientDrawable";
-
-    private static final float CENTRALIZED_CIRCLE_1 = -2;
-    private static final int GRADIENT_RADIUS = 480; // in dp
-    private static final long COLOR_ANIMATION_DURATION = 2000;
-
-    private int mAlpha = 255;
-
-    private float mDensity;
-    private final Paint mPaint;
-    private final Rect mWindowBounds;
-    private final Splat mSplat;
-
-    private int mMainColor;
-    private int mSecondaryColor;
-    private ValueAnimator mColorAnimation;
-    private int mMainColorTo;
-    private int mSecondaryColorTo;
-
-    public GradientDrawable(@NonNull Context context) {
-        mDensity = context.getResources().getDisplayMetrics().density;
-        mSplat = new Splat(0.50f, 1.00f, GRADIENT_RADIUS, CENTRALIZED_CIRCLE_1);
-        mWindowBounds = new Rect();
-
-        mPaint = new Paint();
-        mPaint.setStyle(Paint.Style.FILL);
-    }
-
-    public void setColors(@NonNull ColorExtractor.GradientColors colors) {
-        setColors(colors.getMainColor(), colors.getSecondaryColor(), true);
-    }
-
-    public void setColors(@NonNull ColorExtractor.GradientColors colors, boolean animated) {
-        setColors(colors.getMainColor(), colors.getSecondaryColor(), animated);
-    }
-
-    public void setColors(int mainColor, int secondaryColor, boolean animated) {
-        if (mainColor == mMainColorTo && secondaryColor == mSecondaryColorTo) {
-            return;
-        }
-
-        if (mColorAnimation != null && mColorAnimation.isRunning()) {
-            mColorAnimation.cancel();
-        }
-
-        mMainColorTo = mainColor;
-        mSecondaryColorTo = mainColor;
-
-        if (animated) {
-            final int mainFrom = mMainColor;
-            final int secFrom = mSecondaryColor;
-
-            ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
-            anim.setDuration(COLOR_ANIMATION_DURATION);
-            anim.addUpdateListener(animation -> {
-                float ratio = (float) animation.getAnimatedValue();
-                mMainColor = ColorUtils.blendARGB(mainFrom, mainColor, ratio);
-                mSecondaryColor = ColorUtils.blendARGB(secFrom, secondaryColor, ratio);
-                buildPaints();
-                invalidateSelf();
-            });
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation, boolean isReverse) {
-                    if (mColorAnimation == animation) {
-                        mColorAnimation = null;
-                    }
-                }
-            });
-            anim.setInterpolator(new DecelerateInterpolator());
-            anim.start();
-            mColorAnimation = anim;
-        } else {
-            mMainColor = mainColor;
-            mSecondaryColor = secondaryColor;
-            buildPaints();
-            invalidateSelf();
-        }
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        if (alpha != mAlpha) {
-            mAlpha = alpha;
-            mPaint.setAlpha(mAlpha);
-            invalidateSelf();
-        }
-    }
-
-    @Override
-    public int getAlpha() {
-        return mAlpha;
-    }
-
-    @Override
-    public void setXfermode(@Nullable Xfermode mode) {
-        mPaint.setXfermode(mode);
-        invalidateSelf();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter colorFilter) {
-        mPaint.setColorFilter(colorFilter);
-    }
-
-    @Override
-    public ColorFilter getColorFilter() {
-        return mPaint.getColorFilter();
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    public void setScreenSize(int width, int height) {
-        mWindowBounds.set(0, 0, width, height);
-        setBounds(0, 0, width, height);
-        buildPaints();
-    }
-
-    private void buildPaints() {
-        Rect bounds = mWindowBounds;
-        if (bounds.width() == 0) {
-            return;
-        }
-
-        float w = bounds.width();
-        float h = bounds.height();
-
-        float x = mSplat.x * w;
-        float y = mSplat.y * h;
-
-        float radius = mSplat.radius * mDensity;
-
-        // When we have only a single alpha gradient, we increase quality
-        // (avoiding banding) by merging the background solid color into
-        // the gradient directly
-        RadialGradient radialGradient = new RadialGradient(x, y, radius,
-                mSecondaryColor, mMainColor, Shader.TileMode.CLAMP);
-        mPaint.setShader(radialGradient);
-    }
-
-    @Override
-    public void draw(@NonNull Canvas canvas) {
-        Rect bounds = mWindowBounds;
-        if (bounds.width() == 0) {
-            throw new IllegalStateException("You need to call setScreenSize before drawing.");
-        }
-
-        // Splat each gradient
-        float w = bounds.width();
-        float h = bounds.height();
-
-        float x = mSplat.x * w;
-        float y = mSplat.y * h;
-
-        float radius = Math.max(w, h);
-        canvas.drawRect(x - radius, y - radius, x + radius, y + radius, mPaint);
-    }
-
-    @VisibleForTesting
-    public int getMainColor() {
-        return mMainColor;
-    }
-
-    @VisibleForTesting
-    public int getSecondaryColor() {
-        return mSecondaryColor;
-    }
-
-    static final class Splat {
-        final float x;
-        final float y;
-        final float radius;
-        final float colorIndex;
-
-        Splat(float x, float y, float radius, float colorIndex) {
-            this.x = x;
-            this.y = y;
-            this.radius = radius;
-            this.colorIndex = colorIndex;
-        }
-    }
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java b/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
new file mode 100644
index 0000000..7bd7acf
--- /dev/null
+++ b/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.colorextraction.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Xfermode;
+import android.graphics.drawable.Drawable;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
+
+/**
+ * Drawable used on SysUI scrims.
+ */
+public class ScrimDrawable extends Drawable {
+    private static final String TAG = "ScrimDrawable";
+    private static final long COLOR_ANIMATION_DURATION = 2000;
+
+    private final Paint mPaint;
+    private int mAlpha = 255;
+    private int mMainColor;
+    private ValueAnimator mColorAnimation;
+    private int mMainColorTo;
+
+    public ScrimDrawable() {
+        mPaint = new Paint();
+        mPaint.setStyle(Paint.Style.FILL);
+    }
+
+    /**
+     * Sets the background color.
+     * @param mainColor the color.
+     * @param animated if transition should be interpolated.
+     */
+    public void setColor(int mainColor, boolean animated) {
+        if (mainColor == mMainColorTo) {
+            return;
+        }
+
+        if (mColorAnimation != null && mColorAnimation.isRunning()) {
+            mColorAnimation.cancel();
+        }
+
+        mMainColorTo = mainColor;
+
+        if (animated) {
+            final int mainFrom = mMainColor;
+
+            ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+            anim.setDuration(COLOR_ANIMATION_DURATION);
+            anim.addUpdateListener(animation -> {
+                float ratio = (float) animation.getAnimatedValue();
+                mMainColor = ColorUtils.blendARGB(mainFrom, mainColor, ratio);
+                invalidateSelf();
+            });
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation, boolean isReverse) {
+                    if (mColorAnimation == animation) {
+                        mColorAnimation = null;
+                    }
+                }
+            });
+            anim.setInterpolator(new DecelerateInterpolator());
+            anim.start();
+            mColorAnimation = anim;
+        } else {
+            mMainColor = mainColor;
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        if (alpha != mAlpha) {
+            mAlpha = alpha;
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public int getAlpha() {
+        return mAlpha;
+    }
+
+    @Override
+    public void setXfermode(@Nullable Xfermode mode) {
+        mPaint.setXfermode(mode);
+        invalidateSelf();
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    public ColorFilter getColorFilter() {
+        return mPaint.getColorFilter();
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        mPaint.setColor(mMainColor);
+        mPaint.setAlpha(mAlpha);
+        canvas.drawRect(getBounds(), mPaint);
+    }
+
+    @VisibleForTesting
+    public int getMainColor() {
+        return mMainColor;
+    }
+}
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index b9aab21..d2e71c8 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.app.WallpaperColors;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Color;
 import android.util.Log;
 import android.util.MathUtils;
@@ -51,11 +52,13 @@
 
     private static final boolean DEBUG = true;
 
-    public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
-    public static final int MAIN_COLOR_DARK = 0xff212121;
+    public static final int MAIN_COLOR_LIGHT = 0xffdadce0;
+    public static final int MAIN_COLOR_DARK = 0xff202124;
+    public static final int MAIN_COLOR_REGULAR = 0xff000000;
 
     private final TonalPalette mGreyPalette;
     private final ArrayList<TonalPalette> mTonalPalettes;
+    private final Context mContext;
 
     // Temporary variable to avoid allocations
     private float[] mTmpHSL = new float[3];
@@ -64,6 +67,7 @@
 
         ConfigParser parser = new ConfigParser(context);
         mTonalPalettes = parser.getTonalPalettes();
+        mContext = context;
 
         mGreyPalette = mTonalPalettes.get(0);
         mTonalPalettes.remove(0);
@@ -247,7 +251,20 @@
         boolean light = inWallpaperColors != null
                 && (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT)
                 != 0;
-        final int color = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
+        boolean dark = inWallpaperColors != null
+                && (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME)
+                != 0;
+        final int color;
+        final boolean inNightMode = (mContext.getResources().getConfiguration().uiMode
+                & android.content.res.Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        if (light) {
+            color = MAIN_COLOR_LIGHT;
+        } else if (dark || inNightMode) {
+            color = MAIN_COLOR_DARK;
+        } else {
+            color = MAIN_COLOR_REGULAR;
+        }
         final float[] hsl = new float[3];
         ColorUtils.colorToHSL(color, hsl);
 
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index cb76649..65a63a0 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -457,13 +457,13 @@
                 return;
             }
             mBinding = false;
-            mService = getServiceInterface(service);
             try {
                 service.linkToDeath(AbstractRemoteService.this, 0);
             } catch (RemoteException re) {
                 handleBinderDied();
                 return;
             }
+            mService = getServiceInterface(service);
             handleOnConnectedStateChangedInternal(true);
             mServiceDied = false;
         }
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index b0855f4..1aef573 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -60,7 +60,7 @@
     public static final boolean FW_SYSTEM_USER_SPLIT =
             SystemProperties.getBoolean("ro.fw.system_user_split", false);
     public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER =
-            SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", false);
+            SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", true);
 
     // ------ ro.crypto.* -------- //
     public static final CryptoProperties.state_values CRYPTO_STATE =
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1c0030d..d945e13 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -38,6 +38,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
+
 import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
 
 import android.animation.Animator;
@@ -125,6 +126,8 @@
     // The height of a window which has not in DIP.
     private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
 
+    private static final int SCRIM_LIGHT = 0x99ffffff; // 60% white
+
     public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
             new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
                     Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
@@ -1237,19 +1240,31 @@
 
     private int calculateStatusBarColor() {
         return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_STATUS,
-                mSemiTransparentBarColor, mWindow.mStatusBarColor);
+                mSemiTransparentBarColor, mWindow.mStatusBarColor,
+                getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+                mWindow.mEnsureStatusBarContrastWhenTransparent);
     }
 
     private int calculateNavigationBarColor() {
         return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_NAVIGATION,
-                mSemiTransparentBarColor, mWindow.mNavigationBarColor);
+                mSemiTransparentBarColor, mWindow.mNavigationBarColor,
+                getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                mWindow.mEnsureNavigationBarContrastWhenTransparent
+                        && getContext().getResources().getBoolean(R.bool.config_navBarNeedsScrim));
     }
 
     public static int calculateBarColor(int flags, int translucentFlag, int semiTransparentBarColor,
-            int barColor) {
-        return (flags & translucentFlag) != 0 ? semiTransparentBarColor
-                : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? barColor
-                : Color.BLACK;
+            int barColor, int sysuiVis, int lightSysuiFlag, boolean scrimTransparent) {
+        if ((flags & translucentFlag) != 0) {
+            return semiTransparentBarColor;
+        } else if ((flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
+            return Color.BLACK;
+        } else if (scrimTransparent && barColor == Color.TRANSPARENT) {
+            boolean light = (sysuiVis & lightSysuiFlag) != 0;
+            return light ? SCRIM_LIGHT : semiTransparentBarColor;
+        } else {
+            return barColor;
+        }
     }
 
     private int getCurrentColor(ColorViewState state) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 04559e4..16d6c52 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -50,6 +50,7 @@
 import android.media.session.MediaController;
 import android.media.session.MediaSessionManager;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Parcel;
@@ -247,6 +248,9 @@
     private boolean mForcedStatusBarColor = false;
     private boolean mForcedNavigationBarColor = false;
 
+    boolean mEnsureStatusBarContrastWhenTransparent;
+    boolean mEnsureNavigationBarContrastWhenTransparent;
+
     @UnsupportedAppUsage
     private CharSequence mTitle = null;
 
@@ -2439,6 +2443,7 @@
         final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
         final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
         final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
+        final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q;
         final boolean targetHcNeedsOptions = context.getResources().getBoolean(
                 R.bool.target_honeycomb_needs_options_menu);
         final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
@@ -2457,6 +2462,12 @@
             mNavigationBarDividerColor = a.getColor(R.styleable.Window_navigationBarDividerColor,
                     0x00000000);
         }
+        if (!targetPreQ) {
+            mEnsureStatusBarContrastWhenTransparent = a.getBoolean(
+                    R.styleable.Window_ensureStatusBarContrastWhenTransparent, false);
+            mEnsureNavigationBarContrastWhenTransparent = a.getBoolean(
+                    R.styleable.Window_ensureNavigationBarContrastWhenTransparent, true);
+        }
 
         WindowManager.LayoutParams params = getAttributes();
 
@@ -3845,6 +3856,32 @@
         return mNavigationBarDividerColor;
     }
 
+    @Override
+    public void setEnsureStatusBarContrastWhenTransparent(boolean ensureContrast) {
+        mEnsureStatusBarContrastWhenTransparent = ensureContrast;
+        if (mDecor != null) {
+            mDecor.updateColorViews(null, false /* animate */);
+        }
+    }
+
+    @Override
+    public boolean isEnsureStatusBarContrastWhenTransparent() {
+        return mEnsureStatusBarContrastWhenTransparent;
+    }
+
+    @Override
+    public void setEnsureNavigationBarContrastWhenTransparent(boolean ensureContrast) {
+        mEnsureNavigationBarContrastWhenTransparent = ensureContrast;
+        if (mDecor != null) {
+            mDecor.updateColorViews(null, false /* animate */);
+        }
+    }
+
+    @Override
+    public boolean isEnsureNavigationBarContrastWhenTransparent() {
+        return mEnsureNavigationBarContrastWhenTransparent;
+    }
+
     public void setIsStartingWindow(boolean isStartingWindow) {
         mIsStartingWindow = isStartingWindow;
     }
diff --git a/core/java/com/android/internal/util/MimeIconUtils.java b/core/java/com/android/internal/util/MimeIconUtils.java
index 0b5fa6d..8523b4e 100644
--- a/core/java/com/android/internal/util/MimeIconUtils.java
+++ b/core/java/com/android/internal/util/MimeIconUtils.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ContentResolver.TypeInfo;
+import android.content.ContentResolver.MimeTypeInfo;
 import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.text.TextUtils;
@@ -34,9 +34,9 @@
 
 public class MimeIconUtils {
     @GuardedBy("sCache")
-    private static final ArrayMap<String, TypeInfo> sCache = new ArrayMap<>();
+    private static final ArrayMap<String, MimeTypeInfo> sCache = new ArrayMap<>();
 
-    private static TypeInfo buildTypeInfo(String mimeType, int iconId,
+    private static MimeTypeInfo buildTypeInfo(String mimeType, int iconId,
             int labelId, int extLabelId) {
         final Resources res = Resources.getSystem();
 
@@ -49,10 +49,10 @@
             label = res.getString(labelId);
         }
 
-        return new TypeInfo(Icon.createWithResource(res, iconId), label, label);
+        return new MimeTypeInfo(Icon.createWithResource(res, iconId), label, label);
     }
 
-    private static @Nullable TypeInfo buildTypeInfo(@NonNull String mimeType) {
+    private static @Nullable MimeTypeInfo buildTypeInfo(@NonNull String mimeType) {
         switch (mimeType) {
             case "inode/directory":
             case "vnd.android.document/directory":
@@ -222,7 +222,7 @@
         }
     }
 
-    private static @Nullable TypeInfo buildGenericTypeInfo(@NonNull String mimeType) {
+    private static @Nullable MimeTypeInfo buildGenericTypeInfo(@NonNull String mimeType) {
         // Look for partial matches
         if (mimeType.startsWith("audio/")) {
             return buildTypeInfo(mimeType, R.drawable.ic_doc_audio,
@@ -252,12 +252,12 @@
                 R.string.mime_type_generic, R.string.mime_type_generic_ext);
     }
 
-    public static @NonNull TypeInfo getTypeInfo(@NonNull String mimeType) {
+    public static @NonNull MimeTypeInfo getTypeInfo(@NonNull String mimeType) {
         // Normalize MIME type
         mimeType = mimeType.toLowerCase(Locale.US);
 
         synchronized (sCache) {
-            TypeInfo res = sCache.get(mimeType);
+            MimeTypeInfo res = sCache.get(mimeType);
             if (res == null) {
                 res = buildTypeInfo(mimeType);
                 sCache.put(mimeType, res);
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 29051f1..1c247cb 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <algorithm>
+#include <array>
 #include <memory>
 #include <vector>
 #include <cmath>
@@ -976,6 +977,153 @@
     return OK;
 }
 
+static void undistort(/*inout*/double& x, /*inout*/double& y,
+        const std::array<float, 6>& distortion,
+        const float cx, const float cy, const float f) {
+    double xp = (x - cx) / f;
+    double yp = (y - cy) / f;
+
+    double x2 = xp * xp;
+    double y2 = yp * yp;
+    double r2 = x2 + y2;
+    double xy2 = 2.0 * xp * yp;
+
+    const float k0 = distortion[0];
+    const float k1 = distortion[1];
+    const float k2 = distortion[2];
+    const float k3 = distortion[3];
+    const float p1 = distortion[4];
+    const float p2 = distortion[5];
+
+    double kr = k0 + ((k3 * r2 + k2) * r2 + k1) * r2;
+    double xpp = xp * kr + p1 * xy2 + p2 * (r2 + 2.0 * x2);
+    double ypp = yp * kr + p1 * (r2 + 2.0 * y2) + p2 * xy2;
+
+    x = xpp * f + cx;
+    y = ypp * f + cy;
+    return;
+}
+
+static inline bool unDistortWithinPreCorrArray(
+        double x, double y,
+        const std::array<float, 6>& distortion,
+        const float cx, const float cy, const float f,
+        int preCorrW, int preCorrH) {
+    undistort(x, y, distortion, cx, cy, f);
+    if (x < 0.0 || y < 0.0 || x > preCorrW - 1 || y > preCorrH - 1) {
+        return false;
+    }
+    return true;
+}
+
+static inline bool boxWithinPrecorrectionArray(
+        int left, int top, int right, int bottom,
+        const std::array<float, 6>& distortion,
+        const float& cx, const float& cy, const float& f,
+        const int& preCorrW, const int& preCorrH){
+    // Top row
+    if (!unDistortWithinPreCorrArray(left, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+
+    if (!unDistortWithinPreCorrArray(cx, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+
+    if (!unDistortWithinPreCorrArray(right, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+
+    // Middle row
+    if (!unDistortWithinPreCorrArray(left, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+
+    if (!unDistortWithinPreCorrArray(right, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+
+    // Bottom row
+    if (!unDistortWithinPreCorrArray(left, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+
+    if (!unDistortWithinPreCorrArray(cx, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+
+    if (!unDistortWithinPreCorrArray(right, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+        return false;
+    }
+    return true;
+}
+
+static inline bool scaledBoxWithinPrecorrectionArray(
+        double scale/*must be <= 1.0*/,
+        const std::array<float, 6>& distortion,
+        const float cx, const float cy, const float f,
+        const int preCorrW, const int preCorrH){
+
+    double left = cx * (1.0 - scale);
+    double right = (preCorrW - 1) * scale + cx * (1.0 - scale);
+    double top = cy * (1.0 - scale);
+    double bottom = (preCorrH - 1) * scale + cy * (1.0 - scale);
+
+    return boxWithinPrecorrectionArray(left, top, right, bottom,
+            distortion, cx, cy, f, preCorrW, preCorrH);
+}
+
+static status_t findPostCorrectionScale(
+        double stepSize, double minScale,
+        const std::array<float, 6>& distortion,
+        const float cx, const float cy, const float f,
+        const int preCorrW, const int preCorrH,
+        /*out*/ double* outScale) {
+    if (outScale == nullptr) {
+        ALOGE("%s: outScale must not be null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    for (double scale = 1.0; scale > minScale; scale -= stepSize) {
+        if (scaledBoxWithinPrecorrectionArray(
+                scale, distortion, cx, cy, f, preCorrW, preCorrH)) {
+            *outScale = scale;
+            return OK;
+        }
+    }
+    ALOGE("%s: cannot find cropping scale for lens distortion: stepSize %f, minScale %f",
+            __FUNCTION__, stepSize, minScale);
+    return BAD_VALUE;
+}
+
+// Apply a scale factor to distortion coefficients so that the image is zoomed out and all pixels
+// are sampled within the precorrection array
+static void normalizeLensDistortion(
+        /*inout*/std::array<float, 6>& distortion,
+        float cx, float cy, float f, int preCorrW, int preCorrH) {
+    ALOGV("%s: distortion [%f, %f, %f, %f, %f, %f], (cx,cy) (%f, %f), f %f, (W,H) (%d, %d)",
+            __FUNCTION__, distortion[0], distortion[1], distortion[2],
+            distortion[3], distortion[4], distortion[5],
+            cx, cy, f, preCorrW, preCorrH);
+
+    // Only update distortion coeffients if we can find a good bounding box
+    double scale = 1.0;
+    if (OK == findPostCorrectionScale(0.002, 0.5,
+            distortion, cx, cy, f, preCorrW, preCorrH,
+            /*out*/&scale)) {
+        ALOGV("%s: scaling distortion coefficients by %f", __FUNCTION__, scale);
+        // The formula:
+        // xc = xi * (k0 + k1*r^2 + k2*r^4 + k3*r^6) + k4 * (2*xi*yi) + k5 * (r^2 + 2*xi^2)
+        // To create effective zoom we want to replace xi by xi *m, yi by yi*m and r^2 by r^2*m^2
+        // Factor the extra m power terms into k0~k6
+        std::array<float, 6> scalePowers = {1, 3, 5, 7, 2, 2};
+        for (size_t i = 0; i < 6; i++) {
+            distortion[i] *= pow(scale, scalePowers[i]);
+        }
+    }
+    return;
+}
+
 // ----------------------------------------------------------------------------
 extern "C" {
 
@@ -1086,9 +1234,9 @@
         uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]);
 
         if (!((imageWidth == preWidth && imageHeight == preHeight) ||
-            (imageWidth == pixWidth && imageHeight == pixHeight))) {
+                (imageWidth == pixWidth && imageHeight == pixHeight))) {
             jniThrowException(env, "java/lang/AssertionError",
-                    "Height and width of imate buffer did not match height and width of"
+                    "Height and width of image buffer did not match height and width of"
                     "either the preCorrectionActiveArraySize or the pixelArraySize.");
             return nullptr;
         }
@@ -1793,7 +1941,7 @@
         status_t err = OK;
 
         // Set up rectilinear distortion correction
-        float distortion[6] {1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+        std::array<float, 6> distortion = {1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
         bool gotDistortion = false;
 
         camera_metadata_entry entry4 =
@@ -1810,6 +1958,19 @@
                     results.find(ANDROID_LENS_DISTORTION);
             if (entry3.count == 5) {
                 gotDistortion = true;
+
+
+                // Scale the distortion coefficients to create a zoom in warpped image so that all
+                // pixels are drawn within input image.
+                for (size_t i = 0; i < entry3.count; i++) {
+                    distortion[i+1] = entry3.data.f[i];
+                }
+
+                // TODO b/118690688: deal with the case where RAW size != preCorrSize
+                if (preWidth == imageWidth && preHeight == imageHeight) {
+                    normalizeLensDistortion(distortion, cx, cy, f, preWidth, preHeight);
+                }
+
                 float m_x = std::fmaxf(preWidth-1 - cx, cx);
                 float m_y = std::fmaxf(preHeight-1 - cy, cy);
                 float m_sq = m_x*m_x + m_y*m_y;
@@ -1831,7 +1992,7 @@
                     m / f
                 };
                 for (size_t i = 0; i < entry3.count; i++) {
-                    distortion[i+1] = convCoeff[i] * entry3.data.f[i];
+                    distortion[i+1] *= convCoeff[i];
                 }
             } else {
                 entry3 = results.find(ANDROID_LENS_RADIAL_DISTORTION);
@@ -1859,8 +2020,8 @@
                 }
             }
             if (gotDistortion) {
-                err = builder.addWarpRectilinearForMetadata(distortion, preWidth, preHeight, cx,
-                        cy);
+                err = builder.addWarpRectilinearForMetadata(
+                        distortion.data(), preWidth, preHeight, cx, cy);
                 if (err != OK) {
                     ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
                     jniThrowRuntimeException(env, "failed to add distortion correction.");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c254266..3135c62 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -250,10 +250,11 @@
 
     Rect sourceCrop = rectFromObj(env, sourceCropObj);
     sp<GraphicBuffer> buffer;
+    bool capturedSecureLayers = false;
     status_t res = ScreenshotClient::capture(displayToken, dataspace,
             ui::PixelFormat::RGBA_8888,
             sourceCrop, width, height,
-            useIdentityTransform, rotation, captureSecureLayers, &buffer);
+            useIdentityTransform, rotation, captureSecureLayers, &buffer, capturedSecureLayers);
     if (res != NO_ERROR) {
         return NULL;
     }
@@ -266,7 +267,8 @@
             buffer->getPixelFormat(),
             (jint)buffer->getUsage(),
             (jlong)buffer.get(),
-            namedColorSpace);
+            namedColorSpace,
+            capturedSecureLayers);
 }
 
 static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken,
@@ -315,7 +317,8 @@
                                        buffer->getPixelFormat(),
                                        (jint)buffer->getUsage(),
                                        (jlong)buffer.get(),
-                                       namedColorSpace);
+                                       namedColorSpace,
+                                       false /* capturedSecureLayers */);
 }
 
 static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
@@ -1455,7 +1458,7 @@
             MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
     gScreenshotGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env,
             screenshotGraphicsBufferClazz,
-            "createFromNative", "(IIIIJI)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;");
+            "createFromNative", "(IIIIJIZ)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;");
 
     jclass displayedContentSampleClazz = FindClassOrDie(env,
             "android/hardware/display/DisplayedContentSample");
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 0996352..77ebd02 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -462,7 +462,6 @@
     }
 
     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
-      LOG(INFO) << "Ignoring open file descriptor " << fd;
       continue;
     }
 
@@ -496,7 +495,6 @@
     }
 
     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
-      LOG(INFO) << "Ignoring open file descriptor " << fd;
       continue;
     }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b94eb16..cc3b3a4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1637,8 +1637,8 @@
         android:label="@string/permlab_bluetooth"
         android:protectionLevel="normal" />
 
-    <!-- @SystemApi Allows an application to suspend other apps, which will prevent the user
-         from using them until they are unsuspended.
+    <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the
+         user from using them until they are unsuspended.
          @hide
     -->
     <permission android:name="android.permission.SUSPEND_APPS"
diff --git a/core/res/res/drawable/ic_bluetooth_share_icon.xml b/core/res/res/drawable/ic_bluetooth_share_icon.xml
index 2446402..2152af5 100644
--- a/core/res/res/drawable/ic_bluetooth_share_icon.xml
+++ b/core/res/res/drawable/ic_bluetooth_share_icon.xml
@@ -19,9 +19,9 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24"
-    android:tint="@android:color/accent_device_default">
+    android:tint="@android:color/accent_device_default_light">
 
     <path
         android:fillColor="@android:color/white"
         android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
-</vector>
\ No newline at end of file
+</vector>
diff --git a/core/res/res/drawable/ic_qs_ui_mode_night.xml b/core/res/res/drawable/ic_qs_ui_mode_night.xml
new file mode 100644
index 0000000..7227827
--- /dev/null
+++ b/core/res/res/drawable/ic_qs_ui_mode_night.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,22C17.52,22 22,17.52 22,12 22,6.48 17.52,2 12,2 6.48,2 2,6.48 2,12 2,17.52 6.48,22 12,22ZM12,3.915c3.889,0 8,4.005 8,8.085 0,4.08 -3.927,7.992 -7.928,7.992z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 132e515..c7c293b 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -309,8 +309,8 @@
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"تسجيل الصوت"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بتسجيل الصوت؟"</string>
     <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"النشاط البدني"</string>
-    <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"الوصول إلى نشاطك البدني"</string>
-    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"‏هل تريد السماح للتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى نشاطك البدني؟"</string>
+    <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"الوصول إلى بيانات نشاطك البدني"</string>
+    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"‏هل تريد السماح للتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى بيانات نشاطك البدني؟"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"الكاميرا"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"التقاط صور وتسجيل فيديو"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالتقاط صور وتسجيل فيديو؟"</string>
@@ -1897,7 +1897,7 @@
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"تم الحذف بواسطة المشرف"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"موافق"</string>
     <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"لإطالة عمر البطارية، تساعد ميزة \"توفير شحن البطارية\" على إيقاف أو تقييد نشاط الخلفية وبعض التأثيرات المرئية وغيرها من الميزات التي تستنفد طاقة البطارية. "<annotation id="url">"مزيد من المعلومات"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"لإطالة عمر البطارية، تساعد ميزة \"توفير شحن البطارية\" على إيقاف أو تقييد نشاط الخلفية وبعض التأثيرات المرئية وغيرها من الميزات التي تستنفد طاقة البطارية."</string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"لإطالة عمر البطارية، تساعد ميزة \"توفير شحن البطارية\" على إيقاف أو تقييد النشاط في الخلفية وبعض التأثيرات المرئية وغيرها من الميزات التي تستنفد طاقة البطارية."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"للمساعدة في خفض استخدام البيانات، يمنع توفير البيانات بعض التطبيقات من إرسال البيانات وتلقيها في الخلفية. يمكن للتطبيق الذي تستخدمه الآن الوصول إلى البيانات، ولكن لا يمكنه تنفيذ ذلك كثيرًا. وهذا يعني أن الصور على سبيل المثال لا تظهر حتى تنقر عليها."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"هل تريد تشغيل توفير البيانات؟"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"تشغيل"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 63437e3..778442b 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"এপক আপোনাৰ ফট’ সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"এপক আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ দিয়ে।"</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"এইজন আপুনিয়েই বুলি সত্যাপন কৰক"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"বায়োমেট্ৰিক হাৰ্ডৱেৰ উপলব্ধ নহয়"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"চিনাক্ত কৰিব পৰা নাই"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 1d0ae2d..144d99c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1988,7 +1988,7 @@
     <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Сховішча на прыладзе"</string>
     <string name="adb_debugging_notification_channel_tv" msgid="5537766997350092316">"Адладка USB"</string>
     <string name="time_picker_hour_label" msgid="2979075098868106450">"гадз"</string>
-    <string name="time_picker_minute_label" msgid="5168864173796598399">"хвіліна"</string>
+    <string name="time_picker_minute_label" msgid="5168864173796598399">"хв"</string>
     <string name="time_picker_header_text" msgid="143536825321922567">"Задаць час"</string>
     <string name="time_picker_input_error" msgid="7574999942502513765">"Увядзіце дапушчальны час"</string>
     <string name="time_picker_prompt_label" msgid="7588093983899966783">"Увядзіце час"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 47da68a..21a1195 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1920,7 +1920,7 @@
     <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Хранилище на устройството"</string>
     <string name="adb_debugging_notification_channel_tv" msgid="5537766997350092316">"Отстраняване на грешки през USB"</string>
     <string name="time_picker_hour_label" msgid="2979075098868106450">"час"</string>
-    <string name="time_picker_minute_label" msgid="5168864173796598399">"минута"</string>
+    <string name="time_picker_minute_label" msgid="5168864173796598399">"минути"</string>
     <string name="time_picker_header_text" msgid="143536825321922567">"Задаване на час"</string>
     <string name="time_picker_input_error" msgid="7574999942502513765">"Въведете валиден час"</string>
     <string name="time_picker_prompt_label" msgid="7588093983899966783">"Въведете часа"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 8198ee4..dddd0fc 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -283,7 +283,7 @@
     <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে এই ডিভাইসের লোকেশন অ্যাক্সেস করতে দেবেন?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"আপনি এই অ্যাপ ব্যবহার করার সময়েই শুধু সেটি আপনার লোকেশন অ্যাক্সেস করতে পারবে"</string>
     <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অ্যাপকে এই ডিভাইসের লোকেশন &lt;b&gt;সব সময়&lt;/b&gt; অ্যাক্সেস করার অনুমতি দিতে চান?"</string>
-    <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"এই অ্যাপ ব্যবহার করার সময় বর্তমানে সেটি আপনার লোকেশন অ্যাক্সেস করতে পারে"</string>
+    <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"আপনি যখন অ্যাপটি ব্যবহার করবেন শুধুমাত্র তখনই অ্যাপটি বর্তমান লোকেশন অ্যাক্সেস করতে পারবে।"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"ক্যালেন্ডার"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"আপনার ক্যালেন্ডারে অ্যাক্সেস"</string>
     <string name="permgrouprequest_calendar" msgid="289900767793189421">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-কে আপনার ক্যালেন্ডারে অ্যাক্সেস দেবেন?"</string>
@@ -504,7 +504,7 @@
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"আপনার স্ক্রিন লক অক্ষম করুন"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"কী-লক এবং যেকোনো সংশ্লিষ্ট পাসওয়ার্ড সুরক্ষা অক্ষম করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ উদাহরণস্বরূপ, একটি ইনকামিং ফোন কল গ্রহণ করার সময়ে ফোনটি কী-লক অক্ষম করে, তারপরে কল শেষ হয়ে গেলে কী-লকটিকে আবার সক্ষম করে৷"</string>
     <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"স্ক্রিন লকের জটিলতা জানার অনুরোধ করুন"</string>
-    <string name="permdesc_requestPasswordComplexity" msgid="4730994229754212347">"এটি অ্যাপটিকে স্ক্রিন লকের জটিলতার লেভেল বুঝতে সাহায্য করে (খুব বেশি, মাঝারি, অল্প জটিল বা কোনও জটিলতা নেই), যা স্ক্রিন লকটি সম্ভত কত দীর্ঘ ও সেটির ধরন কীরকম, তার ইঙ্গিত দেয়। এই অ্যাপটি একটি নির্দিষ্ট লেভেল পর্যন্ত স্ক্রিন লক আপডেট করার সাজেশনও দিতে পারে, তবে ব্যবহারকারী তা উপেক্ষা করে অন্য কোথাও চলে যেতে পারেন। মনে রাখবেন যে স্ক্রিন লক প্লেন টেক্সট হিসেবে সংরক্ষণ করা হয় না, তাই অ্যাপ কখনও আসল পাসওয়ার্ড জানতে পারে না।"</string>
+    <string name="permdesc_requestPasswordComplexity" msgid="4730994229754212347">"এটি অ্যাপটিকে স্ক্রিন লকের জটিলতার লেভেল বুঝতে সাহায্য করে (খুব বেশি, মাঝারি, অল্প জটিল বা কোনও জটিলতা নেই), যা স্ক্রিন লকটি সম্ভবত কত দীর্ঘ ও সেটির ধরন কীরকম, তার ইঙ্গিত দেয়। এই অ্যাপটি একটি নির্দিষ্ট লেভেল পর্যন্ত স্ক্রিন লক আপডেট করার সাজেশনও দিতে পারে, তবে ব্যবহারকারী তা উপেক্ষা করে অন্য কোথাও চলে যেতে পারেন। মনে রাখবেন যে স্ক্রিন লক প্লেন টেক্সট হিসেবে সংরক্ষণ করা হয় না, তাই অ্যাপ কখনও আসল পাসওয়ার্ড জানতে পারে না।"</string>
     <string name="permlab_useBiometric" msgid="8837753668509919318">"বায়োমেট্রিক হার্ডওয়্যার ব্যবহার করুন"</string>
     <string name="permdesc_useBiometric" msgid="8389855232721612926">"অ্যাপটিকে যাচাইকরণের জন্য বায়োমেট্রিক হার্ডওয়্যার ব্যবহার করার অনুমতি দেয়"</string>
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার পরিচালনা করুন"</string>
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"অ্যাপকে আপনার ফটো সংগ্রহ পরিবর্তন করার অনুমতি দিন।"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"ডিয়া সংগ্রহ থেকে লোকেশন দেখতে দিন"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"আপনার মিডিয়া সংগ্রহ থেকে লোকেশন দেখতে অ্যাপকে অনুমতি দিন।"</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"আপনার পরিচয় যাচাই করুন"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"যাচাইকরণ বাতিল হয়েছে"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"স্বীকৃত নয়"</string>
@@ -1798,8 +1797,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"আপনার প্রশাসক আপডেট করেছেন"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ঠিক আছে"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ব্যাটারি আরও বেশিক্ষণ চালাতে ব্যাটারি সেভার ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট ও অতিরিক্ত শক্তি খরচ হয় এমন অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে। "<annotation id="url">"আরও জানুন"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ব্যাটারি আরও বেশিক্ষণ চালাতে ব্যাটারি সেভার ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট ও অতিরিক্ত শক্তি খরচ হয় এমন অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে।"</string>
+    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ব্যাটারি আরও বেশিক্ষণ চালাতে ব্যাটারি সেভার ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজুয়াল এফেক্ট ও অতিরিক্ত শক্তি খরচ হয় এমন অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে। "<annotation id="url">"আরও জানুন"</annotation></string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"ব্যাটারি আরও বেশিক্ষণ চালাতে ব্যাটারি সেভার ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজুয়াল এফেক্ট ও অতিরিক্ত শক্তি খরচ হয় এমন অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে।"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ডেটা সেভার চালু করবেন?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"চালু করুন"</string>
@@ -1995,8 +1994,8 @@
     <string name="dynamic_mode_notification_title" msgid="508815255807182035">"সাধারণত যখন চার্জ দেন, তার আগে চার্জ শেষ হয়ে যেতে পারে"</string>
     <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ডিভাইস বেশিক্ষণ চালু রাখতে ব্যাটারি সেভার চালু করা হয়েছে"</string>
     <string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"ব্যাটারি সেভার"</string>
-    <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"চার্জ আবার কম না হওয়া পর্যন্ত ব্যাটারি সেভার আবার চালু হবে না"</string>
-    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"ব্যাটারি পর্যাপ্ত পরিমাণ চার্জ করা হয়েছে। চার্জ আবার কম না হওয়া পর্যন্ত ব্যাটারি সেভার আবার চালু হবে না।"</string>
+    <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"চার্জ কম না হওয়া পর্যন্ত ব্যাটারি সেভার আবার চালু হবে না"</string>
+    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"ব্যাটারি পর্যাপ্ত পরিমাণ চার্জ করা হয়েছে। চার্জ কম না হওয়া পর্যন্ত ব্যাটারি সেভার আবার চালু হবে না।"</string>
     <string name="battery_saver_charged_notification_title" product="default" msgid="2960978289873161288">"ফোনে <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> চার্জ আছে"</string>
     <string name="battery_saver_charged_notification_title" product="tablet" msgid="7555713825806482451">"ট্যাবলেটে <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> চার্জ আছে"</string>
     <string name="battery_saver_charged_notification_title" product="device" msgid="5954873381559605660">"ডিভাইসে <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> চার্জ আছে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index a724827..93705a2 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -283,7 +283,7 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup vašim kontaktima?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"pristupa lokaciji ovog uređaja"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup lokaciji ovog uređaja?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; da pristupi lokaciji ovog uređaja?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"Aplikacija će imati pristup lokaciji isključivo dok je koristite"</string>
     <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"Dozvoliti aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pristup lokaciji uređaja &lt;b&gt;sve vrijeme&lt;/b&gt;?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"Aplikacija trenutno može pristupati lokaciji isključivo dok je koristite"</string>
@@ -1462,7 +1462,7 @@
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Želite li dozvoliti taj zahtjev?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Zahtjev za pristup"</string>
     <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
-    <string name="deny" msgid="2081879885755434506">"Odbijte"</string>
+    <string name="deny" msgid="2081879885755434506">"Odbij"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Upućen zahtjev za odobrenje"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Upućen zahtjev za dozvolu\nza račun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Aplikaciju koristite van poslovnog profila"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index b76d408..b3e1ac6 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -94,7 +94,7 @@
     <string name="notification_channel_sms" msgid="3441746047346135073">"Missatges SMS"</string>
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Missatges de veu"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Trucades per Wi-Fi"</string>
-    <string name="notification_channel_sim" msgid="4052095493875188564">"Estat de la targeta SIM"</string>
+    <string name="notification_channel_sim" msgid="4052095493875188564">"Estat de la SIM"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"L\'altre dispositiu ha sol·licitat el mode TTY COMPLET."</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"L\'altre dispositiu ha sol·licitat el mode TTY HCO."</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"L\'altre dispositiu ha sol·licitat el mode TTY VCO."</string>
@@ -300,8 +300,8 @@
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"accedir a la teva activitat física"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi a la teva activitat física?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Càmera"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"fer fotos i vídeos"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci fotos i vídeos?"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"fer fotos i gravar vídeos"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci fotos i gravi vídeos?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Registres de trucades"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"llegir i editar el registre de trucades del telèfon"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als registres de trucades del telèfon?"</string>
@@ -655,7 +655,7 @@
     <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Fa un seguiment del nombre de contrasenyes incorrectes que s\'han escrit en intentar desbloquejar la pantalla i bloqueja el televisor o n\'esborra totes les dades de l\'usuari si s\'escriuen massa contrasenyes incorrectes."</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Fa un seguiment del nombre de contrasenyes incorrectes que s\'han escrit en intentar desbloquejar la pantalla i bloqueja el telèfon o n\'esborra totes les dades de l\'usuari si s\'escriuen massa contrasenyes incorrectes."</string>
     <string name="policylab_resetPassword" msgid="4934707632423915395">"Canviar el bloqueig de pantalla"</string>
-    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Canvia el bloqueig de pantalla"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Canvia el bloqueig de pantalla."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloquejar la pantalla"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controla com i quan es bloqueja la pantalla."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Esborrar totes les dades"</string>
@@ -1796,8 +1796,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualitzat per l\'administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Suprimit per l\'administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"D\'acord"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Per tal d\'allargar la durada de la bateria, l\'estalvi de bateria desactiva o restringeix les activitats en segon pla, alguns efectes visuals i altres funcions que consumeixen molta energia. "<annotation id="url">"Més informació"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Per tal d\'allargar la durada de la bateria, l\'estalvi de bateria desactiva o restringeix les activitats en segon pla, alguns efectes visuals i altres funcions que consumeixen molta energia."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Per tal de prolongar la durada de la bateria, el mode Estalvi de bateria desactiva o restringeix les activitats en segon pla, alguns efectes visuals i altres funcions que consumeixen molta energia. "<annotation id="url">"Més informació"</annotation></string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"Per tal de prolongar la durada de la bateria, el mode Estalvi de bateria desactiva o restringeix les activitats en segon pla, alguns efectes visuals i altres funcions que consumeixen molta energia."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a dades, però potser ho farà menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Activar Economitzador de dades?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activa"</string>
@@ -1991,7 +1991,7 @@
     <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="dynamic_mode_notification_summary" msgid="2541166298550402690">"S\'ha activat l\'estalvi de bateria per prolongar-ne la durada"</string>
     <string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"Estalvi de bateria"</string>
     <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"L\'estalvi de bateria no es tornarà a activar fins que no tornis a tenir poca bateria"</string>
     <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"La bateria ja està suficientment carregada. L\'estalvi de bateria no es tornarà a activar fins que no tornis a tenir poca bateria."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6a17d70..6322a4a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -577,7 +577,7 @@
   </string-array>
     <string name="face_error_hw_not_available" msgid="396883585636963908">"Gesicht nicht erkannt. Hardware nicht verfügbar."</string>
     <string name="face_error_timeout" msgid="2605673935810019129">"Erkennungszeit überschritten. Noch mal versuchen."</string>
-    <string name="face_error_no_space" msgid="2712120617457553825">"Kein Speicherplatz frei. Bitte alte Gesichtsdaten löschen."</string>
+    <string name="face_error_no_space" msgid="2712120617457553825">"Kein Speicherplatz frei. Bitte erst ein Gesicht löschen."</string>
     <string name="face_error_canceled" msgid="2768146728600802422">"Gesichtserkennung abgebrochen"</string>
     <string name="face_error_user_canceled" msgid="9003022830076496163">"Gesichtserkennung vom Nutzer abgebrochen"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Zu viele Versuche, bitte später noch einmal versuchen"</string>
@@ -1206,8 +1206,8 @@
     <string name="dump_heap_notification_detail" msgid="3993078784053054141">"Heap-Dump wurde erfasst. Tippe, um ihn zu teilen."</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Heap-Dump teilen?"</string>
     <string name="dump_heap_text" msgid="8546022920319781701">"Für den Prozess \"<xliff:g id="PROC">%1$s</xliff:g>\" wurde das Speicherlimit von <xliff:g id="SIZE">%2$s</xliff:g> überschritten. Es steht ein Heap-Dump zur Verfügung, den du mit dem Entwickler teilen kannst. Beachte jedoch unbedingt, dass der Heap-Dump personenbezogene Daten von dir enthalten kann, auf die die App zugreifen kann."</string>
-    <string name="dump_heap_system_text" msgid="3236094872980706024">"Für den Prozess \"<xliff:g id="PROC">%1$s</xliff:g>\" wurde das Prozessspeicherlimit von <xliff:g id="SIZE">%2$s</xliff:g> überschritten. Es steht ein Heap-Dump zur Verfügung, den du teilen kannst. Beachte jedoch unbedingt, dass der Heap-Dump vertrauliche personenbezogene Daten von dir enthalten kann, auf die der Prozess Zugriff hat, einschließlich der von dir eingegebenen Informationen."</string>
-    <string name="dump_heap_ready_text" msgid="1778041771455343067">"Es steht ein Heap-Dump des Prozesses \"<xliff:g id="PROC">%1$s</xliff:g>\" zur Verfügung, den du teilen kannst. Beachte jedoch unbedingt, dass der Heap-Dump vertrauliche personenbezogene Daten von dir enthalten kann, auf die der Prozess Zugriff hat, einschließlich der von dir eingegebenen Informationen."</string>
+    <string name="dump_heap_system_text" msgid="3236094872980706024">"Für den Prozess \"<xliff:g id="PROC">%1$s</xliff:g>\" wurde das Prozessspeicherlimit von <xliff:g id="SIZE">%2$s</xliff:g> überschritten. Es gibt einen Heap-Dump, den du teilen kannst. Beachte jedoch unbedingt, dass der Heap-Dump vertrauliche personenbezogene Daten von dir enthalten kann, auf die der Prozess Zugriff hat, einschließlich der von dir eingegebenen Informationen."</string>
+    <string name="dump_heap_ready_text" msgid="1778041771455343067">"Es gibt einen Heap-Dump des Prozesses \"<xliff:g id="PROC">%1$s</xliff:g>\", den du teilen kannst. Beachte jedoch unbedingt, dass der Heap-Dump vertrauliche personenbezogene Daten von dir enthalten kann, auf die der Prozess Zugriff hat, einschließlich der von dir eingegebenen Informationen."</string>
     <string name="sendText" msgid="5209874571959469142">"Aktion für Text auswählen"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
@@ -1844,7 +1844,7 @@
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Abends unter der Woche"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Wochenende"</string>
     <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Termin"</string>
-    <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Beim Schlafen"</string>
+    <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Schlafen"</string>
     <string name="muted_by" msgid="5942954724562097128">"Einige Töne werden von <xliff:g id="THIRD_PARTY">%1$s</xliff:g> stummgeschaltet"</string>
     <string name="system_error_wipe_data" msgid="6608165524785354962">"Es liegt ein internes Problem mit deinem Gerät vor. Möglicherweise verhält es sich instabil, bis du es auf die Werkseinstellungen zurücksetzt."</string>
     <string name="system_error_manufacturer" msgid="8086872414744210668">"Es liegt ein internes Problem mit deinem Gerät vor. Bitte wende dich diesbezüglich an den Hersteller."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c6557c1..7964e64 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1797,7 +1797,7 @@
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Tu administrador borró este paquete"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string>
     <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"El Ahorro de batería desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones que consumen mucha energía a fin de extender la duración de batería. "<annotation id="url">"Más información"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"El Ahorro de batería desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones que consumen mucha energía a fin de extender la duración de batería."</string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"El Ahorro de batería desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones que consumen mucha energía para extender la duración de la batería."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para reducir el uso de datos, Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar Ahorro de datos?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d15ba97..5e79620 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -133,7 +133,7 @@
     <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi bidezko deiak"</string>
     <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN bidezko deia"</string>
     <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN bidezko deia"</string>
-    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> wifia"</string>
     <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi bidezko deiak | <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wfcSpnFormat_wifi_calling" msgid="4990486735013125329">"Wi-Fi bidezko deiak"</string>
@@ -277,22 +277,22 @@
     <string name="managed_profile_label" msgid="8947929265267690522">"Aldatu laneko profilera"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"atzitu kontaktuak"</string>
-    <string name="permgrouprequest_contacts" msgid="6032805601881764300">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari kontaktuak atzitzea baimendu nahi diozu?"</string>
+    <string name="permgrouprequest_contacts" msgid="6032805601881764300">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari kontaktuak atzitzeko baimena eman nahi diozu?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"atzitu gailuaren kokapena"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari gailuaren kokapena atzitzea baimendu nahi diozu?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari gailuaren kokapena atzitzeko baimena eman nahi diozu?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"Hura erabiltzen ari zarenean soilik atzituko du aplikazioak kokapena"</string>
-    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari gailu honen kokapena &lt;b&gt;beti&lt;/b&gt; atzitzeko baimena eman nahi diozu?"</string>
+    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari gailuaren kokapena &lt;b&gt;beti&lt;/b&gt; atzitzeko baimena eman nahi diozu?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"Aplikazioak hura darabilzunean atzi dezake kokapena"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Egutegia"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"atzitu egutegia"</string>
-    <string name="permgrouprequest_calendar" msgid="289900767793189421">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari egutegia atzitzea baimendu nahi diozu?"</string>
+    <string name="permgrouprequest_calendar" msgid="289900767793189421">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari egutegia atzitzeko baimena eman nahi diozu?"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS mezuak"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"bidali eta ikusi SMS mezuak"</string>
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari SMS mezuak bidaltzea eta ikustea baimendu nahi diozu?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Memoria"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"atzitu gailuko argazkiak, multimedia-edukia eta fitxategiak"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari gailuko argazkiak, multimedia-edukia eta fitxategiak atzitzea baimendu nahi diozu?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari gailuko argazkiak, multimedia-edukia eta fitxategiak atzitzeko baimena eman nahi diozu?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofonoa"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"grabatu audioa"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari audioa grabatzea baimendu nahi diozu?"</string>
@@ -304,13 +304,13 @@
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari argazkiak ateratzea eta bideoak grabatzea baimendu nahi diozu?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Deien erregistroa"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"irakurri telefonoko deien erregistroa eta idatzi bertan"</string>
-    <string name="permgrouprequest_calllog" msgid="8487355309583773267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari telefonoko deien erregistroa atzitzea baimendu nahi diozu?"</string>
+    <string name="permgrouprequest_calllog" msgid="8487355309583773267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari telefonoko deien erregistroa atzitzeko baimena eman nahi diozu?"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefonoa"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"egin eta kudeatu telefono-deiak"</string>
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari telefono-deiak egitea eta kudeatzea baimendu nahi diozu?"</string>
     <string name="permgrouplab_sensors" msgid="4838614103153567532">"Gorputz-sentsoreak"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"atzitu bizi-konstanteei buruzko sentsorearen datuak"</string>
-    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Bizi-konstanteei buruzko sentsorearen datuak atzitzea baimendu nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
+    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Bizi-konstanteei buruzko sentsorearen datuak atzitzeko baimena eman nahi diozu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari?"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Eskuratu leihoko edukia"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Arakatu irekita daukazun leihoko edukia."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktibatu \"Arakatu ukituta\""</string>
@@ -485,7 +485,7 @@
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez tableta soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Wi-Fi sareko gailu guztiei bidalitako paketeak jasotzea baimentzen die aplikazioei multidifusio-helbideak erabilita, ez telebista soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez telefonoa soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
-    <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"atzitu Bluetooth-ezarpenak"</string>
+    <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"atzitu Bluetooth ezarpenak"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Tokiko Bluetooth tableta konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei."</string>
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Tokiko Bluetooth telebista konfiguratzea eta urruneko gailuak hautematea eta haiekin parekatzea baimentzen die aplikazioei."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Tokiko Bluetooth telefonoa konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei."</string>
@@ -1206,8 +1206,8 @@
     <string name="dump_heap_notification_detail" msgid="3993078784053054141">"Sortu da uneko memoria-prozesuaren txostena. Sakatu partekatzeko."</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Uneko memoria-prozesuaren txostena partekatu nahi duzu?"</string>
     <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> prozesuak memoria-muga (<xliff:g id="SIZE">%2$s</xliff:g>) gainditu du. Uneko memoria-prozesuaren txostena sortu da, garatzailearekin parteka dezazun. Kontuz: aplikazioak atzi dezakeen informazio pertsonala izan dezake txosten horrek."</string>
-    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> prozesuak bere memoria-muga (<xliff:g id="SIZE">%2$s</xliff:g>) gainditu du. Memoria-prozesuaren txosten bat duzu erabilgarri, hura partekatu nahi baduzu ere. Kontuz: baliteke txosten horrek prozesuak atzi dezakeen kontuzko informazio pertsonala izatea, eta datu horien barnean zuk idatzitakoak egon daitezke, besteak beste."</string>
-    <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> prozesuaren memoria-prozesuaren txosten bat duzu erabilgarri, hura partekatu nahi baduzu ere. Kontuz: baliteke txosten horrek prozesuak atzi dezakeen kontuzko informazio pertsonala izatea, eta datu horien barnean zuk idatzitakoak egon daitezke, besteak beste."</string>
+    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> prozesuak bere memoria-muga (<xliff:g id="SIZE">%2$s</xliff:g>) gainditu du. Memoria-iraulketaren txosten bat duzu erabilgarri, hura partekatu nahi baduzu ere. Kontuz: baliteke txosten horrek prozesuak atzi dezakeen kontuzko informazio pertsonala izatea eta datu horien barnean zuk idatzitakoak egotea, besteak beste."</string>
+    <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> prozesuaren memoria-iraulketaren txosten bat duzu erabilgarri, hura partekatu nahi baduzu ere. Kontuz: baliteke txosten horrek prozesuak atzi dezakeen kontuzko informazio pertsonala izatea eta datu horien barnean zuk idatzitakoak egotea, besteak beste."</string>
     <string name="sendText" msgid="5209874571959469142">"Aukeratu testurako ekintza"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Tonu-jotzailearen bolumena"</string>
     <string name="volume_music" msgid="5421651157138628171">"Multimedia-edukiaren bolumena"</string>
@@ -1272,7 +1272,7 @@
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
   <string-array name="network_switch_type_name">
     <item msgid="3979506840912951943">"datu-konexioa"</item>
-    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="75483255295529161">"Wifia"</item>
     <item msgid="6862614801537202646">"Bluetooth-a"</item>
     <item msgid="5447331121797802871">"Ethernet"</item>
     <item msgid="8257233890381651999">"VPN"</item>
@@ -1845,7 +1845,7 @@
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Lanegunetako gaua"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Asteburua"</string>
     <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Gertaera"</string>
-    <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Lo egitean"</string>
+    <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Lo egiteko"</string>
     <string name="muted_by" msgid="5942954724562097128">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> soinu batzuk isilarazten ari da"</string>
     <string name="system_error_wipe_data" msgid="6608165524785354962">"Barneko arazo bat dago zure gailuan eta agian ezegonkor egongo da jatorrizko datuak berrezartzen dituzun arte."</string>
     <string name="system_error_manufacturer" msgid="8086872414744210668">"Barneko arazo bat dago zure gailuan. Xehetasunak jakiteko, jarri fabrikatzailearekin harremanetan."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 11cf22a..50c7185 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à vos activités physiques?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Appareil photo"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"prendre des photos et filmer des vidéos"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à prendre des photos et à filmer des vidéos?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à prendre des photos et à filmer des vidéos?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Journaux d\'appels"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"lire et écrire le journal des appels téléphoniques"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder à vos journaux d\'appels?"</string>
@@ -1844,7 +1844,7 @@
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Soirs de semaine"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Fin de semaine"</string>
     <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Événement"</string>
-    <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Dormir"</string>
+    <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Sommeil"</string>
     <string name="muted_by" msgid="5942954724562097128">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> désactive certains sons"</string>
     <string name="system_error_wipe_data" msgid="6608165524785354962">"Un problème interne est survenu avec votre appareil. Il se peut qu\'il soit instable jusqu\'à ce que vous le réinitialisiez à sa configuration d\'usine."</string>
     <string name="system_error_manufacturer" msgid="8086872414744210668">"Un problème interne est survenu avec votre appareil. Communiquez avec le fabricant pour obtenir plus de détails."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 12660fb..23e424e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -280,7 +280,7 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'accéder à vos contacts ?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"accéder à la position de l\'appareil"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'accéder à la position de cet appareil ?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"Permettre à l\'application &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'accéder à la position de cet appareil ?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"L\'application n\'a accès à la position de l\'appareil que lorsqu\'elle est ouverte"</string>
     <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder &lt;b&gt;en permanence&lt;/b&gt; à la position de cet appareil ?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"L\'application peut actuellement accéder à la position uniquement pendant que vous l\'utilisez"</string>
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à accéder à votre activité physique ?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Appareil photo"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"prendre des photos et enregistrer des vidéos"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; de prendre des photos et de filmer des vidéos ?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à prendre des photos et enregistrer des vidéos ?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Journaux d\'appels"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"Lire et écrire les journaux d\'appels du téléphone"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'accéder aux journaux d\'appels de votre téléphone ?"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index d7a241a..393fcbe 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1202,12 +1202,12 @@
     <string name="new_app_action" msgid="6694851182870774403">"Abrir a aplicación <xliff:g id="NEW_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="5894852887817332322">"A aplicación <xliff:g id="OLD_APP">%1$s</xliff:g> pecharase sen gardar o contido"</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> superou o límite de memoria"</string>
-    <string name="dump_heap_ready_notification" msgid="1162196579925048701">"O baleirado de montóns de <xliff:g id="PROC">%1$s</xliff:g> está listo"</string>
-    <string name="dump_heap_notification_detail" msgid="3993078784053054141">"Recompilouse un baleirado de montóns. Toca para compartilo."</string>
-    <string name="dump_heap_title" msgid="5864292264307651673">"Queres compartir o baleirado de montóns?"</string>
-    <string name="dump_heap_text" msgid="8546022920319781701">"O proceso <xliff:g id="PROC">%1$s</xliff:g> superou o seu límite de memoria de <xliff:g id="SIZE">%2$s</xliff:g>. Tes dispoñible un baleirado de montóns para compartir co seu programador. Ten coidado, xa que pode conter información persoal á que pode acceder a aplicación."</string>
-    <string name="dump_heap_system_text" msgid="3236094872980706024">"O proceso <xliff:g id="PROC">%1$s</xliff:g> superou o seu límite de memoria, <xliff:g id="SIZE">%2$s</xliff:g>. Tes dispoñible un baleirado de montóns para compartilo. Ten coidado, xa que quizais conteña información persoal confidencial á que se pode acceder durante o proceso e que pode incluír os datos que escribiches."</string>
-    <string name="dump_heap_ready_text" msgid="1778041771455343067">"Tes dispoñible un baleirado de montóns do proceso <xliff:g id="PROC">%1$s</xliff:g> para compartilo. Ten coidado, xa que é posible que conteña información persoal confidencial á que se pode acceder durante o proceso e que pode incluír os datos que escribiches."</string>
+    <string name="dump_heap_ready_notification" msgid="1162196579925048701">"O baleirado da zona de memoria dinámica de <xliff:g id="PROC">%1$s</xliff:g> está listo"</string>
+    <string name="dump_heap_notification_detail" msgid="3993078784053054141">"Recompilouse un baleirado da zona de memoria dinámica. Toca para compartilo."</string>
+    <string name="dump_heap_title" msgid="5864292264307651673">"Queres compartir o baleirado da zona de memoria dinámica?"</string>
+    <string name="dump_heap_text" msgid="8546022920319781701">"O proceso <xliff:g id="PROC">%1$s</xliff:g> superou o seu límite de memoria de <xliff:g id="SIZE">%2$s</xliff:g>. Tes dispoñible un baleirado da zona de memoria dinámica para compartir co seu programador. Ten coidado, xa que pode conter información persoal á que pode acceder a aplicación."</string>
+    <string name="dump_heap_system_text" msgid="3236094872980706024">"O proceso <xliff:g id="PROC">%1$s</xliff:g> superou o seu límite de memoria, <xliff:g id="SIZE">%2$s</xliff:g>. Tes dispoñible un baleirado da zona de memoria dinámica para compartilo. Ten coidado, xa que quizais conteña información persoal confidencial á que se pode acceder durante o proceso e que pode incluír os datos que escribiches."</string>
+    <string name="dump_heap_ready_text" msgid="1778041771455343067">"Tes dispoñible un baleirado da zona de memoria dinámica do proceso <xliff:g id="PROC">%1$s</xliff:g> para compartilo. Ten coidado, xa que é posible que conteña información persoal confidencial á que se pode acceder durante o proceso e que pode incluír os datos que escribiches."</string>
     <string name="sendText" msgid="5209874571959469142">"Seleccionar unha acción para o texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume do timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume dos elementos multimedia"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index d2b6fc9..80206a3 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"એપને તમારો ફોટો સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"આપના મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવા"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"આ તમે જ છો તેનો પુરાવો આપો"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"પ્રમાણીકરણ રદ કર્યું"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ઓળખાયેલ નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5933297..0e5123b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -160,15 +160,15 @@
     <string name="httpErrorAuth" msgid="1435065629438044534">"प्रमाणीकृत नहीं किया जा सका."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"प्रॉक्‍सी सर्वर द्वारा प्रमाणीकरण असफल था."</string>
     <string name="httpErrorConnect" msgid="8714273236364640549">"सर्वर से कनेक्ट नहीं किया जा सका."</string>
-    <string name="httpErrorIO" msgid="2340558197489302188">"सर्वर से संचार नहीं किया जा सका. बाद में पुन: प्रयास करें."</string>
-    <string name="httpErrorTimeout" msgid="4743403703762883954">"सर्वर से कनेक्‍शन का समय समाप्त हुआ."</string>
+    <string name="httpErrorIO" msgid="2340558197489302188">"सर्वर से संचार नहीं किया जा सका. बाद में फिर से प्रयास करें."</string>
+    <string name="httpErrorTimeout" msgid="4743403703762883954">"सर्वर से कनेक्‍शन का समय खत्म हुआ."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"पेज में कई ऐसे कई वेबलिंक हैं जो दूसरे सर्वर पर ले जाते हैं."</string>
     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"प्रोटोकॉल समर्थित नहीं है."</string>
     <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"सुरक्षित कनेक्शन स्थापित नहीं किया जा सका."</string>
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"यूआरएल गलत होने की वजह से पेज नहीं खोला जा सका."</string>
     <string name="httpErrorFile" msgid="2170788515052558676">"फ़ाइल पर नहीं पहुंचा जा सका."</string>
     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"अनुरोधित फ़ाइल नहीं मिल सकी."</string>
-    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"बहुत सारे अनुरोधों का संसाधन हो रहा है. बाद में पुन: प्रयास करें."</string>
+    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"बहुत सारे अनुरोधों का संसाधन हो रहा है. बाद में फिर से प्रयास करें."</string>
     <string name="notification_title" msgid="8967710025036163822">"<xliff:g id="ACCOUNT">%1$s</xliff:g> के लिए प्रवेश गड़बड़ी"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"समन्वयन"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="7036196943673524858">"सिंक नहीं किया जा सकता"</string>
@@ -234,7 +234,7 @@
     <skip />
     <string name="bugreport_message" msgid="398447048750350456">"इससे ईमेल भेजने के लिए, आपके डिवाइस की मौजूदा स्थिति से जुड़ी जानकारी इकट्ठा की जाएगी. गड़बड़ी की रिपोर्ट बनना शुरू होने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया इंतज़ार करें."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"सहभागी रिपोर्ट"</string>
-    <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"अधिकांश परिस्थितियों में इसका उपयोग करें. यह आपको रिपोर्ट की प्रगति ट्रैक करने देता है, समस्या के बारे में अधिक विवरण डालने देता है और स्क्रीनशॉट लेने देता है. यह आपको ऐसे कम उपयोग किए गए अनुभाग मिटाने दे सकता है जिनकी रिपोर्ट करने में अधिक समय लगता है."</string>
+    <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"ज़्यादातर परिस्थितियों में इसका उपयोग करें. यह आपको रिपोर्ट की प्रगति ट्रैक करने देता है, समस्या के बारे में अधिक विवरण डालने देता है और स्क्रीनशॉट लेने देता है. यह आपको ऐसे कम उपयोग किए गए अनुभाग मिटाने दे सकता है जिनकी रिपोर्ट करने में अधिक समय लगता है."</string>
     <string name="bugreport_option_full_title" msgid="6354382025840076439">"पूर्ण रिपोर्ट"</string>
     <string name="bugreport_option_full_summary" msgid="7210859858969115745">"जब आपका डिवाइस ठीक से काम नहीं कर रहा हो या बहुत धीमा हो या जब आपको रिपोर्ट के सभी भागों की ज़रूरत हो, तो सिस्टम से कम से कम रोक-टोक के लिए इस विकल्प का इस्तेमाल करें. यह आपको ज़्यादा जानकारी डालने या अतिरिक्त स्क्रीनशॉट लेने नहीं देता."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
@@ -283,7 +283,7 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने संपर्क देखने की अनुमति देना चाहते हैं?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"जगह"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"इस डिवाइस की जगह तक पहुंचने दें"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस की \'जगह की जानकारी\' ऐक्सेस करने की अनुमति देना चाहते हैं?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को इस डिवाइस की \'जगह की जानकारी\' एक्सेस करने की अनुमति देना चाहते हैं?"</string>
     <!-- no translation found for permgrouprequestdetail_location (1347189607421252902) -->
     <skip />
     <!-- no translation found for permgroupbackgroundrequest_location (5039063878675613235) -->
@@ -366,12 +366,12 @@
     <string name="permdesc_getTasks" msgid="7454215995847658102">"ऐप को माजूदा समय में और हाल ही में चल रही कार्रवाइयों के बारे में जानकारी निकालने देता है. इससे ऐप डिवाइस पर इस्तेमाल किए गए ऐप के बारे में जानकारी खोज सकता है."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"प्रोफ़ाइल और डिवाइस स्‍वामियों को प्रबंधित करें"</string>
     <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"ऐप्‍स को प्रोफ़ाइल स्‍वामी और डिवाइस स्‍वामी सेट करने दें."</string>
-    <string name="permlab_reorderTasks" msgid="2018575526934422779">"चल रहे ऐप्स पुन: क्रमित करें"</string>
+    <string name="permlab_reorderTasks" msgid="2018575526934422779">"चल रहे ऐप्स फिर से क्रमित करें"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"ऐप्स  को कार्यों को अग्रभूमि और पृष्‍ठभूमि पर ले जाने देता है. ऐप्स  आपके इनपुट के बिना यह कर सकता है."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"कार मोड चालू करें"</string>
     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"ऐप्स  को कार मोड सक्षम करने देता है."</string>
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"अन्‍य ऐप्स बंद करें"</string>
-    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"ऐप्स  को अन्‍य ऐप्स की पृष्ठभूमि प्रक्रियाओं को समाप्त करने देता है. यह अन्य ऐप्स  का चलना रोक सकता है."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"ऐप्स  को अन्‍य ऐप्स की पृष्ठभूमि प्रक्रियाओं को खत्म करने देता है. यह अन्य ऐप्स  का चलना रोक सकता है."</string>
     <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"यह ऐप्लिकेशन दूसरे ऐप्लिकेशन के ऊपर दिखाई दे सकता है"</string>
     <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"यह ऐप्लिकेशन, दूसरे ऐप्लिकेशन के ऊपर या स्क्रीन के अन्य भागों पर दिखाई दे सकता है. इससे ऐप्लिकेशन के सामान्य उपयोग में बाधा आ सकती है और दूसरे ऐप्लिकेशन के दिखाई देने के तरीकों में बदलाव हो सकता है."</string>
     <string name="permlab_runInBackground" msgid="7365290743781858803">"बैकग्राउंड में चलता है"</string>
@@ -389,13 +389,13 @@
     <string name="permlab_writeSettings" msgid="2226195290955224730">"सिस्‍टम सेटिंग बदलें"</string>
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"ऐप्स  को सिस्टम सेटिंग डेटा संशोधित करने देता है. दुर्भावनापूर्ण ऐप्स  आपके सिस्टम के कॉन्फ़िगरेशन को दूषित कर सकते हैं."</string>
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"प्रारंभ होने पर चलाएं"</string>
-    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"ऐप्स  को सिस्टम द्वारा बूटिंग पूर्ण करते ही स्वतः आरंभ करने देता है. इससे टैबलेट को आरंभ होने में अधिक समय लग सकता है और ऐप्स  को निरंतर चलाकर संपूर्ण टैबलेट को धीमा करने देता है."</string>
+    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"ऐप्स  को सिस्टम द्वारा बूटिंग पूर्ण करते ही अपने आप आरंभ करने देता है. इससे टैबलेट को आरंभ होने में अधिक समय लग सकता है और ऐप्स  को निरंतर चलाकर संपूर्ण टैबलेट को धीमा करने देता है."</string>
     <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"सिस्‍टम के चालू होते ही ऐप को अपने आप शुरू होने देती है. इससे टीवी को चालू होने में ज़्यादा समय लग सकता है और ऐप के लगातार चलते रहने से पूरा टैबलेट धीमा हो सकता है."</string>
     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"सिस्‍टम के चालू होते ही ऐप को अपने आप शुरू होने देती है. इससे फ़ोन को चालू होने में ज़्यादा समय लग सकता है और ऐप के लगातार चलते रहने से पूरा फ़ोन धीमा हो सकता है."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"स्टिकी प्रसारण भेजें"</string>
-    <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"ऐप्स को स्‍टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, टैबलेट की बहुत अधिक मेमोरी का उपयोग करके उसे धीमा या अस्‍थिर कर सकता है."</string>
+    <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"ऐप्स को स्‍टिकी प्रसारण भेजने देता है, जो प्रसारण खत्म होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, टैबलेट की बहुत अधिक मेमोरी का उपयोग करके उसे धीमा या अस्‍थिर कर सकता है."</string>
     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"ऐप को स्‍िटकी प्रसारण भेजने देती है, जो प्रसारण बंद होने के बाद भी बने रहते हैं. अत्‍यधिक उपयोग से टीवी धीमा या अस्‍थिर हो सकता है जिससे वह बहुत सारी मेमोरी का उपयोग कर सकता है."</string>
-    <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"ऐप्स को स्‍टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, फ़ोन की बहुत अधिक मेमोरी का उपयोग करके उसे धीमा या अस्‍थिर कर सकता है."</string>
+    <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"ऐप्स को स्‍टिकी प्रसारण भेजने देता है, जो प्रसारण खत्म होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, फ़ोन की बहुत अधिक मेमोरी का उपयोग करके उसे धीमा या अस्‍थिर कर सकता है."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"अपने संपर्क पढ़ें"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"ऐप को आपके टैबलेट पर मौजूद आपके संपर्कों का डेटा पढ़ने देती है, जिसमें ये भी शामिल है कि आपने कुछ ख़ास लोगों से कितनी बार कॉल, ईमेल, या कुछ और तरीकों से बातचीत की. यह अनुमति ऐप को आपका संपर्क डेटा सेव करने देती है और धोखा देने वाले ऐप संपर्क डेटा को आपकी जानकारी के बिना शेयर कर सकते हैं."</string>
     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"ऐप को आपके टीवी पर मौजूद आपके संपर्कों का डेटा पढ़ने देती है, जिसमें ये भी शामिल है कि आपने कुछ ख़ास लोगों से कितनी बार कॉल, ईमेल, या कुछ और तरीकों से बातचीत की. यह अनुमति ऐप को आपका संपर्क डेटा सेव करने देती है और धोखा देने वाले ऐप संपर्क डेटा को आपकी जानकारी के बिना शेयर कर सकते हैं."</string>
@@ -511,7 +511,7 @@
     <string name="permlab_nfc" msgid="4423351274757876953">"नियर फ़ील्‍ड कम्‍यूनिकेशन नियंत्रित करें"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"ऐप्स  को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्‍क्रीन लॉक अक्षम करें"</string>
-    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
+    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल खत्म होने पर कीलॉक को फिर से सक्षम कर देता है."</string>
     <!-- no translation found for permlab_requestPasswordComplexity (202650535669249674) -->
     <skip />
     <!-- no translation found for permdesc_requestPasswordComplexity (4730994229754212347) -->
@@ -530,15 +530,14 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"इससे ऐप्लिकेशन को आपके फ़ोटो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"अपने मीडिया संग्रह से जगह की जानकारी एक्सेस करने की अनुमति दें"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी एक्सेस करने की अनुमति दी जाती है."</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"अपनी पहचान की पुष्टि करें"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेयर उपलब्ध नहीं है"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"प्रमाणीकरण रद्द किया गया"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"पहचान नहीं हो पाई"</string>
     <string name="biometric_error_canceled" msgid="349665227864885880">"प्रमाणीकरण रद्द किया गया"</string>
     <string name="biometric_error_device_not_secured" msgid="6583143098363528349">"पिन, पैटर्न या पासवर्ड सेट नहीं है"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"आंशिक फ़िंगरप्रिंट की पहचान की गई. कृपया पुनः प्रयास करें."</string>
-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"फ़िंगरप्रिंट संसाधित नहीं हो सका. कृपया पुन: प्रयास करें."</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"फ़िंगरप्रिंट संसाधित नहीं हो सका. कृपया फिर से प्रयास करें."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"फ़िंगरप्रिंट सेंसर गंदा है. कृपया साफ़ करें और फिर कोशिश करें."</string>
     <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"उंगली बहुत तेज़ी से चलाई गई है. कृपया फिर से कोशिश करें."</string>
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"उंगली बहुत धीरे चलाई गई. कृपया फिर से कोशिश करें."</string>
@@ -549,12 +548,12 @@
     <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"चेहरे की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फ़िंगरप्रिंट हार्डवेयर उपलब्ध नहीं है."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"फ़िंगरप्रिंट को संग्रहित नहीं किया जा सका. कृपया कोई मौजूदा फ़िंगरप्रिंट निकालें."</string>
-    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"फ़िंगरप्रिंट का समय समाप्त हो गया. पुनः प्रयास करें."</string>
+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"फ़िंगरप्रिंट का समय खत्म हो गया. पुनः प्रयास करें."</string>
     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"फ़िंगरप्रिंट क्रियान्वयन रोक दिया गया."</string>
     <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"उपयोगकर्ता ने फिंगरप्रिंट की पुष्टि की कार्रवाई रद्द कर दी है."</string>
-    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"बहुत अधिक प्रयास कर लिए गए हैं. बाद में पुन: प्रयास करें."</string>
+    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"बहुत अधिक प्रयास कर लिए गए हैं. बाद में फिर से प्रयास करें."</string>
     <string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"बहुत अधिक कोशिशें. फ़िंगरप्रिंट सेंसर अक्षम है."</string>
-    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"पुन: प्रयास करें."</string>
+    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"फिर से प्रयास करें."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string>
     <string name="fingerprint_error_hw_not_present" msgid="409523969613176352">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string>
     <string name="fingerprint_name_template" msgid="5870957565512716938">"फ़िंगरप्रिंट <xliff:g id="FINGERID">%d</xliff:g>"</string>
@@ -604,25 +603,18 @@
     <skip />
   <string-array name="face_acquired_vendor">
   </string-array>
-    <!-- no translation found for face_error_hw_not_available (396883585636963908) -->
-    <skip />
+    <string name="face_error_hw_not_available" msgid="396883585636963908">"चेहरा नहीं पहचान पा रहे. हार्डवेयर उपलब्ध नहीं है."</string>
     <!-- no translation found for face_error_timeout (2605673935810019129) -->
     <skip />
-    <!-- no translation found for face_error_no_space (2712120617457553825) -->
-    <skip />
-    <!-- no translation found for face_error_canceled (2768146728600802422) -->
-    <skip />
-    <!-- no translation found for face_error_user_canceled (9003022830076496163) -->
-    <skip />
+    <string name="face_error_no_space" msgid="2712120617457553825">"चेहरे का नया डेटा सेव नहीं हो सकता. कोई पुराना डेटा मिटाएं."</string>
+    <string name="face_error_canceled" msgid="2768146728600802422">"चेहरा पहचानने की कार्रवाई रद्द की गई"</string>
+    <string name="face_error_user_canceled" msgid="9003022830076496163">"उपयोगकर्ता ने \'चेहरे की पहचान\' रद्द कर दी."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"कई बार कोशिश की गई. बाद में कोशिश करें."</string>
-    <!-- no translation found for face_error_lockout_permanent (3485837851962070925) -->
-    <skip />
+    <string name="face_error_lockout_permanent" msgid="3485837851962070925">"कई बार कोशिश की जा चुकी है. \'चेहरे की पहचान\' बंद कर दी गई."</string>
     <!-- no translation found for face_error_unable_to_process (4940944939691171539) -->
     <skip />
-    <!-- no translation found for face_error_not_enrolled (2600952202843125796) -->
-    <skip />
-    <!-- no translation found for face_error_hw_not_present (1317845121210260372) -->
-    <skip />
+    <string name="face_error_not_enrolled" msgid="2600952202843125796">"आपने डिवाइस पर \'चेहरे की पहचान\' सेट नहीं की है."</string>
+    <string name="face_error_hw_not_present" msgid="1317845121210260372">"इस डिवाइस पर \'चेहरे की पहचान\' सुविधा काम नहीं करती."</string>
     <string name="face_name_template" msgid="7004562145809595384">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string>
   <string-array name="face_error_vendor">
   </string-array>
@@ -687,7 +679,7 @@
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्‍क्रीन लॉक पासवर्ड और पिन की लंबाई और उनमें स्वीकृत वर्णों को नियंत्रित करना."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"स्‍क्रीन अनलॉक करने के की कोशिशों पर नज़र रखना"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"स्‍क्रीन को अनलॉक करते समय गलत लिखे गए पासवर्ड की संख्‍या पर निगरानी करें, और बहुत अधिक बार गलत पासवर्ड लिखे जाने पर टैबलेट लॉक करें या टैबलेट का संपूर्ण डेटा मिटाएं."</string>
-    <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्‍क्रीन को अनलॉक करते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें और यदि बहुत अधिक गलत पासवर्ड लिखे जाते हैं तो टीवी को लॉक करें या टीवी का सभी डेटा मिटा दें."</string>
+    <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्‍क्रीन को अनलॉक करते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें और अगर बहुत अधिक गलत पासवर्ड लिखे जाते हैं तो टीवी को लॉक करें या टीवी का सभी डेटा मिटा दें."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"स्क्रीन को अनलॉक करते समय जितनी बार गलत पासवर्ड लिखा गया है, उसकी संख्या पर नज़र रखना और अगर बहुत बार गलत पासवर्ड डाले गए हैं, तो फ़ोन को लॉक कर देना या फ़ोन का सारा डेटा मिटा देना."</string>
     <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्‍क्रीन का लॉक खोलते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें, और अगर बार-बार अधिक पासवर्ड लिखे जाते हैं तो टैबलेट को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string>
     <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्‍क्रीन का लॉक खोलते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें, और अगर बार-बार गलत पासवर्ड लिखा जाता है तो टीवी को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string>
@@ -765,7 +757,7 @@
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"घर का फ़ैक्स"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"पेजर"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"अन्य"</string>
-    <string name="phoneTypeCallback" msgid="2712175203065678206">"पुन: कॉल करें"</string>
+    <string name="phoneTypeCallback" msgid="2712175203065678206">"फिर से कॉल करें"</string>
     <string name="phoneTypeCar" msgid="8738360689616716982">"कार"</string>
     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"कंपनी का मुख्य"</string>
     <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
@@ -871,19 +863,19 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"कृपया उपयोग के लिए गाइड देखें या ग्राहक सहायता से संपर्क करें."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"सिम कार्ड लॉक किया गया है."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"सिम कार्ड अनलॉक कर रहा है…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत बनाया है. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपने अपना पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत बनाया है. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपने अपना पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"आपने अपना पिन <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके टैबलेट को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"आपने अपना अनलॉक पैटन <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टीवी को अपने Google साइन-इन का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके फ़ोन को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके टैबलेट को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"आपने अपना अनलॉक पैटन <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टीवी को अपने Google साइन-इन का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके फ़ोन को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"आप टैबलेट का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश कर चुके हैं. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, टैबलेट फ़ैक्ट्री डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"आपने टीवी का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और बार गलत कोशिश करने पर, टीवी को फ़ैक्ट्री डिफ़ॉल्‍ट पर रीसेट कर दिया जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"आप फ़ोन का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश कर चुके हैं. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, फ़ोन फ़ैक्ट्री डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"आप टैबलेट को गलत तरीके से <xliff:g id="NUMBER">%d</xliff:g> बार अनलॉक करने का प्रयास कर चुके हैं. टैबलेट अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"आपने टीवी को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. अब टीवी को फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट कर दिया जाएगा."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"आप फ़ोन को गलत तरीके से <xliff:g id="NUMBER">%d</xliff:g> बार अनलॉक करने का प्रयास कर चुके हैं. फ़ोन अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
-    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"आकार भूल गए?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"खाता अनलॉक"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"बहुत अधिक आकार प्रयास"</string>
@@ -914,7 +906,7 @@
     <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"कैमरा"</string>
     <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"मीडिया नियंत्रण"</string>
     <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"विजेट फिर से क्रमित करना प्रारंभ."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"विजेट फिर से क्रमित करना समाप्त."</string>
+    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"विजेट फिर से क्रमित करना खत्म."</string>
     <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को हटा दिया गया."</string>
     <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र का विस्तार करें."</string>
     <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलॉक."</string>
@@ -1193,7 +1185,7 @@
     <string name="aerr_restart" msgid="7581308074153624475">"ऐप्लिकेशन फिर से खोलें"</string>
     <string name="aerr_report" msgid="5371800241488400617">"फ़ीडबैक भेजें"</string>
     <string name="aerr_close" msgid="2991640326563991340">"बंद करें"</string>
-    <string name="aerr_mute" msgid="1974781923723235953">"डिवाइस पुन: प्रारंभ होने तक म्यूट करें"</string>
+    <string name="aerr_mute" msgid="1974781923723235953">"डिवाइस फिर से प्रारंभ होने तक म्यूट करें"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"प्रतीक्षा करें"</string>
     <string name="aerr_close_app" msgid="3269334853724920302">"ऐप बंद करें"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
@@ -1246,10 +1238,8 @@
     <string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप शेयर करें?"</string>
     <!-- no translation found for dump_heap_text (8546022920319781701) -->
     <skip />
-    <!-- no translation found for dump_heap_system_text (3236094872980706024) -->
-    <skip />
-    <!-- no translation found for dump_heap_ready_text (1778041771455343067) -->
-    <skip />
+    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया अपनी <xliff:g id="SIZE">%2$s</xliff:g> की मेमोरी सीमा पार कर चुकी है. एक हीप डंप शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी संवेदनशील निजी जानकारी भी शामिल हो सकती है जिसका एक्सेस प्रोसेस के पास हो. इसमें आपके टाइप किए गए शब्दों का डेटा भी शामिल है."</string>
+    <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रिया का हीप डंप शेयर किए जाने के लिए तैयार है. सावधान रहें: इस हीप डंप में कोई ऐसी संवेदनशील निजी जानकारी शामिल हो सकती है जिसका एक्सेस प्रोसेस के पास हो. इसमें आपके टाइप किए गए शब्दों का डेटा भी शामिल है."</string>
     <string name="sendText" msgid="5209874571959469142">"मैसेज करने के लिए कोई कार्रवाई चुनें"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्‍यूम"</string>
     <string name="volume_music" msgid="5421651157138628171">"मीडिया वॉल्‍यूम"</string>
@@ -1361,7 +1351,7 @@
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"हमेशा अनुमति दें"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"कभी भी अनुमति न दें"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"सिमकार्ड निकाला गया"</string>
-    <string name="sim_removed_message" msgid="2333164559970958645">"मान्‍य सि‍म कार्ड डालकर पुन: प्रारंभ करने तक मोबाइल नेटवर्क अनुपलब्‍ध रहेगा."</string>
+    <string name="sim_removed_message" msgid="2333164559970958645">"मान्‍य सि‍म कार्ड डालकर फिर से प्रारंभ करने तक मोबाइल नेटवर्क अनुपलब्‍ध रहेगा."</string>
     <string name="sim_done_button" msgid="827949989369963775">"हो गया"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"सिम कार्ड जोड़ा गया"</string>
     <string name="sim_added_message" msgid="6599945301141050216">"मोबाइल नेटवर्क की पहुंच पाने लिए अपना डिवाइस फिर से चालू करें."</string>
@@ -1411,7 +1401,7 @@
     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
     <string name="select_input_method" msgid="4653387336791222978">"इनपुट पद्धति चुनें"</string>
     <string name="show_ime" msgid="2506087537466597099">"सामान्य कीबोर्ड के सक्रिय होने के दौरान इसे स्‍क्रीन पर बनाए रखें"</string>
-    <string name="hardware" msgid="194658061510127999">"वर्चूअल कीबोर्ड दिखाएं"</string>
+    <string name="hardware" msgid="194658061510127999">"वर्चुअल कीबोर्ड दिखाएं"</string>
     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"सामान्य कीबोर्ड कॉन्फ़िगर करें"</string>
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1655,10 +1645,8 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ओवरले #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", सुरक्षित"</string>
-    <!-- no translation found for activity_starter_block_bg_activity_starts_permissive (6995473033438879646) -->
-    <skip />
-    <!-- no translation found for activity_starter_block_bg_activity_starts_enforcing (3317816771072146229) -->
-    <skip />
+    <string name="activity_starter_block_bg_activity_starts_permissive" msgid="6995473033438879646">"आने वाले Q बिल्ड में <xliff:g id="PACKAGENAME">%1$s</xliff:g> के बैकग्राउंड में गतिविधि शुरू करने पर रोक लगा दी जाएगी. इस बारे में जानने के लिए g.co/dev/bgblock पर जाएं."</string>
+    <string name="activity_starter_block_bg_activity_starts_enforcing" msgid="3317816771072146229">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> के बैकग्राउंड में गतिविधि शुरू करने पर रोक लगा दी गई है. इस बारे में जानने के लिए g.co/dev/bgblock पर जाएं."</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत पैटर्न डाला गया है"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
@@ -1678,7 +1666,7 @@
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"गलत PIN कोड."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ऐसा PIN लिखें, जो 4 से 8 अंकों का हो."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK कोड 8 अंकों का होना चाहिए."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड फिर से डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से साइन इन करें."</string>
@@ -1688,18 +1676,18 @@
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"उपयोगकर्ता नाम या पासवर्ड गलत है"</string>
     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जाँच की जा रही है…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"आप टैबलेट का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश कर चुके हैं. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, टैबलेट फ़ैक्ट्री डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"आप टीवी का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश कर चुके हैं. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर टीवी को फ़ैक्ट्री डिफ़ॉल्‍ट पर रीसेट कर दिया जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"आप फ़ोन का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश कर चुके हैं. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर फ़ोन फ़ैक्ट्री डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"आप टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. टैबलेट अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"आपने टीवी को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. अब टीवी को फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट कर दिया जाएगा."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. फ़ोन अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टैबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टैबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपको किसी ईमेल खाते के ज़रिये अपने टीवी को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"वॉल्यूम को सुझाए गए स्तर से ऊपर बढ़ाएं?\n\nअत्यधिक वॉल्यूम पर अधिक समय तक सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string>
@@ -1822,8 +1810,8 @@
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN मेल नहीं खाते हैं. फिर से कोशिश करें."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN बहुत छोटा है. कम से कम 4 अंकों का होना चाहिए."</string>
     <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
-      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें</item>
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> सेकंड में फिर से प्रयास करें</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंड में फिर से प्रयास करें</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"बाद में फिर से प्रयास करें"</string>
     <string name="immersive_cling_title" msgid="8394201622932303336">"आप पूरे स्क्रीन पर देख रहे हैं"</string>
@@ -1958,7 +1946,7 @@
     <string name="app_info" msgid="6856026610594615344">"ऐप्लिकेशन की जानकारी"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="demo_starting_message" msgid="5268556852031489931">"डेमो प्रारंभ हो रहा है…"</string>
-    <string name="demo_restarting_message" msgid="952118052531642451">"डिवाइस पुन: रीसेट कर रहा है…"</string>
+    <string name="demo_restarting_message" msgid="952118052531642451">"डिवाइस फिर से रीसेट कर रहा है…"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"अक्षम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"कॉन्फ़्रेंस कॉल"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"टूलटिप"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 4edf36e..2962785 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -140,7 +140,7 @@
     <string name="wfcSpnFormat_wifi" msgid="1892673884655959773">"Wi-Fi"</string>
     <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="1336669776254502831">"Chiamate Wi-Fi"</string>
     <string name="wfcSpnFormat_vowifi" msgid="1765176406171272629">"VoWifi"</string>
-    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Non attiva"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="7335489823608689868">"Chiamata tramite Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="7081742743152286290">"Chiamata su rete mobile"</string>
     <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Solo Wi-Fi"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index c0fa639..1f1df8f 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -307,7 +307,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"‏האם לאפשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; גישה לפעילות הגופנית שלך?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"מצלמה"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"צילום תמונות והקלטת וידאו"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה לצלם תמונות וסרטונים?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"‏לאשר לאפליקציה של &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לצלם תמונות וסרטונים?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"יומני שיחות"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"קריאה וכתיבה של יומן השיחות של הטלפון"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה ליומני השיחות של הטלפון?"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 17169e1..50bbca4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"運動データへのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"カメラ"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"写真と動画の撮影"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"写真と動画の撮影を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"写真と動画の撮影を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"通話履歴"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"通話履歴の読み取りと書き込み"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"通話履歴へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
@@ -545,7 +545,7 @@
     <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"もう一度お試しください。"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"指紋が登録されていません。"</string>
     <string name="fingerprint_error_hw_not_present" msgid="409523969613176352">"このデバイスには指紋認証センサーがありません。"</string>
-    <string name="fingerprint_name_template" msgid="5870957565512716938">"指紋<xliff:g id="FINGERID">%d</xliff:g>"</string>
+    <string name="fingerprint_name_template" msgid="5870957565512716938">"指紋 <xliff:g id="FINGERID">%d</xliff:g>"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指紋アイコン"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index ac8a6df..d465a52 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1843,7 +1843,7 @@
     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"ავარიული პაუზა"</string>
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"სამუშაო კვირის ღამე"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"შაბათ-კვირა"</string>
-    <string name="zen_mode_default_events_name" msgid="8158334939013085363">"მოვლენა"</string>
+    <string name="zen_mode_default_events_name" msgid="8158334939013085363">"მოვლენისას"</string>
     <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"ძილისას"</string>
     <string name="muted_by" msgid="5942954724562097128">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ზოგიერთ ხმას ადუმებს"</string>
     <string name="system_error_wipe_data" msgid="6608165524785354962">"ფიქსირდება თქვენი მ ოწყობილობის შიდა პრობლემა და შეიძლება არასტაბილური იყოს, სანამ ქარხნულ მონაცემების არ განაახლებთ."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 74488b5..aa3c1a8 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -283,7 +283,7 @@
     <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына құрылғының орналасқан жері туралы мәліметтерді пайдалануға рұқсат берілсін бе?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"Қолданбаны пайдалану кезінде ғана оған геодеректеріңізді көруге рұқсат етіледі."</string>
     <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына құрылғының геодеректері &lt;b&gt;үнемі&lt;/b&gt; көрсетіліп тұрсын ба?"</string>
-    <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"Қолданба геодеректерді тек жұмыс кезінде ғана пайдалана алады"</string>
+    <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"Қолданба геодеректерді тек жұмыс кезінде ғана пайдалана алады."</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнтізбе"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"күнтізбеге кіру"</string>
     <string name="permgrouprequest_calendar" msgid="289900767793189421">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасына күнтізбеге кіруге рұқсат берілсін бе?"</string>
@@ -553,7 +553,7 @@
     <string name="permdesc_manageFace" msgid="8919637120670185330">"Қолданбаға пайдаланатын бет үлгілерін енгізу және жою әдістерін шақыруға мүмкіндік береді."</string>
     <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"бетті тану жабдығын пайдалану"</string>
     <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Қолданбаға бетті тану жабдығын қолдануға рұқсат етеді"</string>
-    <string name="face_acquired_insufficient" msgid="2767330364802375742">"Дәл бет деректері алынбады. Әрекетті қайталаңыз."</string>
+    <string name="face_acquired_insufficient" msgid="2767330364802375742">"Бет деректері дұрыс алынбады. Әрекетті қайталаңыз."</string>
     <string name="face_acquired_too_bright" msgid="5005650874582450967">"Тым ашық. Күңгірттеу жарық керек."</string>
     <string name="face_acquired_too_dark" msgid="1966194696381394616">"Тым қараңғы. Молырақ жарық керек."</string>
     <string name="face_acquired_too_close" msgid="1401011882624272753">"Телефонды алшақ ұстаңыз."</string>
@@ -576,7 +576,7 @@
   <string-array name="face_acquired_vendor">
   </string-array>
     <string name="face_error_hw_not_available" msgid="396883585636963908">"Бетті тану мүмкін емес. Жабдық қолжетімді емес."</string>
-    <string name="face_error_timeout" msgid="2605673935810019129">"Бет тануды күту уақыты бітті. Әрекетті қайталаңыз."</string>
+    <string name="face_error_timeout" msgid="2605673935810019129">"Бетті тану уақыты бітті. Әрекетті қайталаңыз."</string>
     <string name="face_error_no_space" msgid="2712120617457553825">"Жаңа бетті сақтау мүмкін емес. Алдымен ескісін жойыңыз."</string>
     <string name="face_error_canceled" msgid="2768146728600802422">"Бетті танудан бас тартылды."</string>
     <string name="face_error_user_canceled" msgid="9003022830076496163">"Пайдаланушы бетті тану әрекетінен бас тартты."</string>
@@ -1210,7 +1210,7 @@
     <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> процесінің дамп файлы бөлісуге дайын. Бұл дамп файлында процесс кезінде пайдаланылған кез келген құпия жеке ақпарат (соның ішінде сіз енгізген деректер) болуы мүмкін екенін ескеріңіз."</string>
     <string name="sendText" msgid="5209874571959469142">"Мәтін үшін әрекет таңдау"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Қоңырау шырылының қаттылығы"</string>
-    <string name="volume_music" msgid="5421651157138628171">"Meдиа дыбысының қаттылығы"</string>
+    <string name="volume_music" msgid="5421651157138628171">"Mультимeдиа дыбыс деңгейі"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth арқылы ойнату"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Үнсіз қоңырау әуенін орнату"</string>
     <string name="volume_call" msgid="3941680041282788711">"Келетін қоңырау дыбысының қаттылығы"</string>
@@ -1220,8 +1220,8 @@
     <string name="volume_unknown" msgid="1400219669770445902">"Дыбыс қаттылығы"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Bluetooth дыбысының қаттылығы"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Қоңырау әуенінің дыбыс қаттылығы"</string>
-    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Қоңырау дыбысының қаттылығы"</string>
-    <string name="volume_icon_description_media" msgid="4217311719665194215">"Meдиа дыбысының қаттылығы"</string>
+    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Қоңыраудағы дыбыс деңгейі"</string>
+    <string name="volume_icon_description_media" msgid="4217311719665194215">"Mультимeдиа дыбыс деңгейі"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Хабар дыбысының қаттылығы"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Әдепкі рингтон"</string>
     <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Әдепкі (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 9e2f718..8c49811 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -578,7 +578,7 @@
     <string name="face_error_hw_not_available" msgid="396883585636963908">"មិនអាច​ផ្ទៀងផ្ទាត់​មុខបានទេ។ មិនមាន​ហាតវែរទេ។"</string>
     <string name="face_error_timeout" msgid="2605673935810019129">"ការសម្គាល់​មុខ​បាន​អស់ម៉ោង។ សូមព្យាយាមម្ដងទៀត។"</string>
     <string name="face_error_no_space" msgid="2712120617457553825">"មិនអាច​ផ្ទុកទិន្នន័យទម្រង់​មុខថ្មី​បានទេ។ សូមលុបទិន្នន័យទម្រង់​មុខចាស់ជាមុនសិន។"</string>
-    <string name="face_error_canceled" msgid="2768146728600802422">"បាន​បោះបង់​ប្រតិបត្តិការចាប់​ទម្រង់មុខ។"</string>
+    <string name="face_error_canceled" msgid="2768146728600802422">"បាន​បោះបង់​ប្រតិបត្តិការចាប់​ទម្រង់មុខ"</string>
     <string name="face_error_user_canceled" msgid="9003022830076496163">"ការផ្ទៀងផ្ទាត់មុខ​ត្រូវបានបោះបង់​ដោយអ្នកប្រើប្រាស់"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
     <string name="face_error_lockout_permanent" msgid="3485837851962070925">"ព្យាយាមចូលច្រើនពេក។ បានបិទ​ការផ្ទៀងផ្ទាត់មុខ។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 52e8bc7..c0f0f44 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಿ"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"ಇದು ನೀವೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ಬಯೋಮೆಟ್ರಿಕ್ ಹಾರ್ಡ್‌ವೇರ್‌ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
@@ -528,7 +527,7 @@
     <string name="biometric_error_device_not_secured" msgid="6583143098363528349">"ಪಿನ್, ಪ್ಯಾಟರ್ನ್ ಅಥವಾ ಪಾಸ್‌ವರ್ಡ್ ಸೆಟ್ ಮಾಡಿಲ್ಲ"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ಭಾಗಶಃ ಬೆರಳಚ್ಚು ಪತ್ತೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ಬೆರಳಚ್ಚು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ಬೆರಳಚ್ಚು ಸೆನ್ಸಾರ್ ಕೊಳೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಅದನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ಬೆರಳಚ್ಚು ಸೆನ್ಸರ್ ಮಲಿನಗೊಂಡಿದೆ. ದಯವಿಟ್ಟು ಅದನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"ಬೆರಳನ್ನು ಅತಿ ವೇಗವಾಗಿ ಸರಿಸಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ಬೆರಳನ್ನು ತುಂಬಾ ನಿಧಾನವಾಗಿ ಸರಿಸಲಾಗಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
   <string-array name="fingerprint_acquired_vendor">
@@ -1206,7 +1205,7 @@
     <string name="dump_heap_ready_notification" msgid="1162196579925048701">"<xliff:g id="PROC">%1$s</xliff:g> ಹೀಪ್ ಡಂಪ್ ಸಿದ್ಧವಾಗಿದೆ"</string>
     <string name="dump_heap_notification_detail" msgid="3993078784053054141">"ಹೀಪ್ ಡಂಪ್ ಅನ್ನು ಸಂಗ್ರಹಿಸಲಾಗಿದೆ; ಹಂಚಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"ಹೀಪ್ ಡಂಪ್ ಹಂಚಿಕೊಳ್ಳುವುದೇ?"</string>
-    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> ಪ್ರಕ್ರಿಯೆಯು ತನ್ನ <xliff:g id="SIZE">%2$s</xliff:g> ಮೆಮೊರಿ ಮಿತಿಯನ್ನು ಮೀರಿದೆ. ಅದರ ಡೆವಲಪರ್ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲು ಹಂಚಿಕೊಳ್ಳಲು ನಿಮಗಾಗಿ ಹೀಪ್ ಡಂಪ್ ಲಭ್ಯವಿದೆ. ಎಚ್ಚರಿಕೆ: ಈ ಹೀಪ್ ಡಂಪ್, ಪ್ರಕ್ರಿಯೆಯು ಪ್ರವೇಶ ಹೊಂದಿರುವ ಯಾವುದೇ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು."</string>
+    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> ಪ್ರಕ್ರಿಯೆಯು ತನ್ನ <xliff:g id="SIZE">%2$s</xliff:g> ಮೆಮೊರಿ ಮಿತಿಯನ್ನು ಮೀರಿದೆ. ಅದರ ಡೆವಲಪರ್ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲು ನಿಮಗಾಗಿ ಹೀಪ್ ಡಂಪ್ ಲಭ್ಯವಿದೆ. ಎಚ್ಚರಿಕೆ: ಈ ಹೀಪ್ ಡಂಪ್, ಅಪ್ಲಿಕೇಶನ್ ಪ್ರವೇಶ ಹೊಂದಿರುವ ನಿಮ್ಮ ಯಾವುದೇ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು."</string>
     <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> ಪ್ರಕ್ರಿಯೆಯು ತನ್ನ <xliff:g id="SIZE">%2$s</xliff:g> ಮೆಮೊರಿ ಮಿತಿಯನ್ನು ಮೀರಿದೆ. ಹಂಚಿಕೊಳ್ಳಲು ನಿಮಗಾಗಿ ಹೀಪ್ ಡಂಪ್ ಲಭ್ಯವಿದೆ. ಎಚ್ಚರಿಕೆ: ಈ ಹೀಪ್ ಡಂಪ್, ಪ್ರಕ್ರಿಯೆಯು ಯಾವುದೇ ಸೂಕ್ಷ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಗೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರಬಹುದು, ಇದು ನೀವು ಟೈಪ್ ಮಾಡಿದ ವಿಷಯಗಳನ್ನು ಸಹ ಒಳಗೊಂಡಿರಬಹುದು."</string>
     <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> ನ ಪ್ರಕ್ರಿಯೆಯ ಹೀಪ್ ಡಂಪ್ ನಿಮಗಾಗಿ ಹಂಚಿಕೊಳ್ಳಲು ಲಭ್ಯವಿದೆ. ಎಚ್ಚರಿಕೆ: ಈ ಹೀಪ್ ಡಂಪ್, ಪ್ರಕ್ರಿಯೆಯು ಯಾವುದೇ ಸೂಕ್ಷ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಗೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರಬಹುದು, ಇದು ನೀವು ಟೈಪ್ ಮಾಡಿದ ವಿಷಯಗಳನ್ನು ಸಹ ಒಳಗೊಂಡಿರಬಹುದು."</string>
     <string name="sendText" msgid="5209874571959469142">"ಪಠ್ಯಕ್ಕೆ ಕ್ರಿಯೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
@@ -1350,8 +1349,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="adb_active_notification_message" msgid="7463062450474107752">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string>
-    <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವುದು ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವುದು ಮೋಡ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಫ್ಯಾಕ್ಟರಿ ರಿಸೆಟ್ ಮಾಡಬೇಕು."</string>
+    <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವಿಕೆ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವಿಕೆ ಮೋಡ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಫ್ಯಾಕ್ಟರಿ ರಿಸೆಟ್ ಮಾಡಬೇಕು."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB ಪೋರ್ಟ್‌ನಲ್ಲಿ ದ್ರವ ಅಥವಾ ಧೂಳಿನ ಕಣಗಳಿವೆ"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ಪೋರ್ಟ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="usb_contaminant_not_detected_title" msgid="4202417484434906086">"USB ಪೋರ್ಟ್ ಬಳಸಲು ಸುರಕ್ಷಿತವಾಗಿದೆ"</string>
@@ -1996,7 +1995,7 @@
     <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ಬ್ಯಾಟರಿ ಅವಧಿ ಹೆಚ್ಚಿಸಲು ಬ್ಯಾಟರಿ ಸೇವರ್ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"ಬ್ಯಾಟರಿ ಸೇವರ್"</string>
     <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"ಇನ್ನೊಮ್ಮೆ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಾಗುವವರೆಗೂ ಬ್ಯಾಟರಿ ಸೇವರ್ ಮರುಸಕ್ರಿಯವಾಗುವುದಿಲ್ಲ"</string>
-    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"ಸಾಕಾಗುವಷ್ಟು ಬ್ಯಾಟರಿಯನ್ನು ಚಾರ್ಜ್ ಮಾಡಲಾಗಿದೆ. ಇನ್ನೊಮ್ಮೆ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಾಗುವವರೆಗೂ ಬ್ಯಾಟರಿ ಸೇವರ್ ಮರುಸಕ್ರಿಯವಾಗುವುದಿಲ್ಲ."</string>
+    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"ಬ್ಯಾಟರಿಯನ್ನು ಬೇಕಾಗಿರುವಷ್ಟು ಮಟ್ಟಕ್ಕೆ ಚಾರ್ಜ್ ಮಾಡಲಾಗಿದೆ. ಇನ್ನೊಮ್ಮೆ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಾಗುವವರೆಗೂ ಬ್ಯಾಟರಿ ಸೇವರ್ ಮರುಸಕ್ರಿಯವಾಗುವುದಿಲ್ಲ."</string>
     <string name="battery_saver_charged_notification_title" product="default" msgid="2960978289873161288">"ಫೋನ್ <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
     <string name="battery_saver_charged_notification_title" product="tablet" msgid="7555713825806482451">"ಟ್ಯಾಬ್ಲೆಟ್ <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
     <string name="battery_saver_charged_notification_title" product="device" msgid="5954873381559605660">"ಸಾಧನ <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5422aed..bc278e2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1843,7 +1843,7 @@
     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"다운타임"</string>
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"평일 밤"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"주말"</string>
-    <string name="zen_mode_default_events_name" msgid="8158334939013085363">"일정"</string>
+    <string name="zen_mode_default_events_name" msgid="8158334939013085363">"캘린더 일정"</string>
     <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"수면 중"</string>
     <string name="muted_by" msgid="5942954724562097128">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>(이)가 일부 소리를 음소거함"</string>
     <string name="system_error_wipe_data" msgid="6608165524785354962">"사용 중인 기기 내부에 문제가 발생했습니다. 초기화할 때까지 불안정할 수 있습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 6003127..8810aeb 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -655,7 +655,7 @@
     <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Экрандын кулпусун ачуу учурунда туура эмес терилген сырсөздөрдү тескөө жана сырсөз өтө көп жолу туура эмес терилген болсо, сыналгыны кулпулап же бул колдонуучунун бардык дайындарын тазалап салуу."</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Экрандын кулпусун ачуу учурунда туура эмес терилген сырсөздөрдү тескөө жана сырсөз өтө көп жолу туура эмес терилген болсо, телефонду кулпулап же бул колдонуучунун бардык дайындарын тазалап салуу."</string>
     <string name="policylab_resetPassword" msgid="4934707632423915395">"Экран кулпусун өзгөртүү"</string>
-    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Экран кулпусун өзгөртүү."</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Экран кулпусун өзгөртөт."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Экранды кулпулоо"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Экран качан жана кантип кулпулана турганын башкарат."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Бардык маалыматты өчүрүү"</string>
@@ -675,7 +675,7 @@
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Камераларды өчүрүү"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Түзмөктүн бардык камераларын колдонууга тыюу салуу."</string>
     <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Функцияларды өчүрүү"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Экранды кулпулоо функцияларынын айрымдарын колдонууга тыюу салуу"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Экранды кулпулаган функциялардын айрымдарын колдонууга тыюу салат."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Үй"</item>
     <item msgid="869923650527136615">"Мобилдик"</item>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index a529258..7f347c8 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -528,7 +528,7 @@
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откриен е делумен отпечаток. Обидете се повторно."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Отпечатокот не можеше да се обработи. Обидете се повторно."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензорот за отпечатоци е валкан. Исчистете го и обидете се повторно."</string>
-    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Прстот се дрижеше пребрзо. Обидете се повторно."</string>
+    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Прстот се движеше пребрзо. Обидете се повторно."</string>
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Прстот се движеше премногу бавно. Обидете се повторно."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
@@ -1362,7 +1362,7 @@
     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛИ"</string>
     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
     <string name="select_input_method" msgid="4653387336791222978">"Одбери метод на внес"</string>
-    <string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
+    <string name="show_ime" msgid="2506087537466597099">"Прикажувај ја на екранот додека е активна физичката тастатура"</string>
     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелна тастатура"</string>
     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигурирајте физичка тастатура"</string>
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index af69c65..4962885 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -141,10 +141,8 @@
     <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="1336669776254502831">"വൈഫൈ കോളിംഗ്"</string>
     <string name="wfcSpnFormat_vowifi" msgid="1765176406171272629">"Voവൈഫൈ"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ഓഫ്"</string>
-    <!-- no translation found for wfc_mode_wifi_preferred_summary (7335489823608689868) -->
-    <skip />
-    <!-- no translation found for wfc_mode_cellular_preferred_summary (7081742743152286290) -->
-    <skip />
+    <string name="wfc_mode_wifi_preferred_summary" msgid="7335489823608689868">"വൈഫൈ മുഖേനയുള്ള കോൾ"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="7081742743152286290">"മൊബൈൽ നെറ്റ്‌വർക്ക് മുഖേനയുള്ള കോൾ"</string>
     <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"വൈഫൈ മാത്രം"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: കൈമാറിയില്ല"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -230,8 +228,7 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"ബഗ് റിപ്പോർട്ട്"</string>
     <string name="global_action_logout" msgid="935179188218826050">"സെഷൻ അവസാനിപ്പിക്കുക"</string>
     <string name="global_action_screenshot" msgid="8329831278085426283">"സ്‌ക്രീൻഷോട്ട്"</string>
-    <!-- no translation found for bugreport_title (5981047024855257269) -->
-    <skip />
+    <string name="bugreport_title" msgid="5981047024855257269">"ബഗ് റിപ്പോർട്ട്"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ഒരു ഇമെയിൽ സന്ദേശമായി അയയ്‌ക്കുന്നതിന്, ഇത് നിങ്ങളുടെ നിലവിലെ ഉപകരണ നിലയെക്കുറിച്ചുള്ള വിവരങ്ങൾ ശേഖരിക്കും. ബഗ് റിപ്പോർട്ട് ആരംഭിക്കുന്നതിൽ നിന്ന് ഇത് അയയ്‌ക്കാനായി തയ്യാറാകുന്നതുവരെ അൽപ്പസമയമെടുക്കും; ക്ഷമയോടെ കാത്തിരിക്കുക."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ഇന്റരാക്റ്റീവ് റിപ്പോർട്ട്"</string>
     <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"മിക്ക സാഹചര്യങ്ങളിലും ഇത് ഉപയോഗിക്കുക. റിപ്പോർട്ടിന്റെ പുരോഗതി കാണാനും പ്രശ്നത്തെ കുറിച്ചുള്ള കൂടുതൽ വിശദാംശങ്ങൾ നൽകാനും സ്ക്രീൻഷോട്ടുകൾ എടുക്കാനും ഇത് അനുവദിക്കുന്നു. റിപ്പോർട്ടുചെയ്യാൻ നീണ്ട സമയം എടുക്കുന്നതും നിങ്ങൾ കുറച്ച് ഉപയോഗിക്കുന്നതുമായ ചില വിഭാഗങ്ങളെ ഇത് വിട്ടുകളഞ്ഞേക്കാം."</string>
@@ -284,12 +281,9 @@
     <string name="permgrouplab_location" msgid="7275582855722310164">"ലൊക്കേഷൻ"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യാൻ"</string>
     <string name="permgrouprequest_location" msgid="3788275734953323491">"ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
-    <!-- no translation found for permgrouprequestdetail_location (1347189607421252902) -->
-    <skip />
-    <!-- no translation found for permgroupbackgroundrequest_location (5039063878675613235) -->
-    <skip />
-    <!-- no translation found for permgroupbackgroundrequestdetail_location (4597006851453417387) -->
-    <skip />
+    <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"നിങ്ങൾ ആപ്പ് ഉപയോഗിക്കുമ്പോൾ മാത്രമേ അതിന് ലൊക്കേഷൻ ആക്‌സസ് ലഭിക്കൂ."</string>
+    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാൻ എപ്പോഴും അനുവദിക്കണോ?"</string>
+    <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"നിലവിൽ, ഉപയോഗിക്കുമ്പോൾ മാത്രം ആപ്പിന് ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാം"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"കലണ്ടർ"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"നിങ്ങളുടെ കലണ്ടർ ആക്‌സസ്സ് ചെയ്യുക"</string>
     <string name="permgrouprequest_calendar" msgid="289900767793189421">"നിങ്ങളുടെ കലണ്ടർ ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
@@ -509,10 +503,8 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"നിയർ ഫീൽഡ് കമ്മ്യൂണിക്കേഷൻ (NFC) ടാഗുകളുമായും കാർഡുകളുമായും റീഡറുകളുമായുള്ള ആശയവിനിമയത്തിന് അപ്ലിക്കേഷനുകളെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"നിങ്ങളുടെ സ്‌ക്രീൻ ലോക്ക് പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"കീലോക്കും ഏതെങ്കിലും അനുബന്ധ പാസ്‌വേഡ് സുരക്ഷയും പ്രവർത്തനരഹിതമാക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ഒരു ഇൻകമിംഗ് കോൾ സ്വീകരിക്കുമ്പോൾ ഫോൺ കീലോക്ക് പ്രവർത്തനരഹിതമാക്കുന്നു, കോൾ അവസാനിക്കുമ്പോൾ കീലോക്ക് വീണ്ടും പ്രവർത്തനക്ഷമമാകുന്നു."</string>
-    <!-- no translation found for permlab_requestPasswordComplexity (202650535669249674) -->
-    <skip />
-    <!-- no translation found for permdesc_requestPasswordComplexity (4730994229754212347) -->
-    <skip />
+    <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"സ്‌ക്രീൻ ലോക്ക് സങ്കീർണ്ണത അഭ്യർത്ഥിക്കുക"</string>
+    <string name="permdesc_requestPasswordComplexity" msgid="4730994229754212347">"സ്ക്രീൻ ലോക്കിന്റെ സാധ്യമായ നീളവും തരവും സൂചിപ്പിക്കുന്ന, അതിന്റെ സങ്കീർണ്ണത നില (ഉയർന്നത്, ഇടത്തരം, കുറഞ്ഞത് അല്ലെങ്കിൽ ഒന്നുമില്ല) മനസ്സിലാക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു. സ്‌ക്രീൻ ലോക്ക് ഒരു പ്രത്യേക തലത്തിലേക്ക് അപ്ഡേറ്റ് ചെയ്യാൻ ഉപയോക്താക്കളെ നിർദ്ദേശിക്കാനും ആപ്പിനാവും, പക്ഷെ ഉപയോക്താക്കൾക്ക് എളുപ്പത്തിൽ അവഗണിക്കാനും മറ്റൊന്നിലേക്ക് നാവിഗേറ്റ് ചെയ്യാനുമാവും. പ്ലെയിൻടെക്‌സ്‌റ്റിൽ സ്ക്രീൻ ലോക്ക് സംഭരിക്കപ്പെട്ടിട്ടില്ലെന്ന കാര്യം ശ്രദ്ധിക്കുക, അതിനാൽ ആപ്പിന് കൃത്യമായ പാസ്‌വേഡ് അറിയില്ല."</string>
     <string name="permlab_useBiometric" msgid="8837753668509919318">"ബയോമെട്രിക് ഹാർ‌ഡ്‌വെയർ ഉപയോഗിക്കുക"</string>
     <string name="permdesc_useBiometric" msgid="8389855232721612926">"പരിശോധിച്ചുറപ്പിക്കുന്നതിനായി, ബയോമെട്രിക് ഹാർഡ്‌വെയർ ഉപയോഗിക്കാൻ ആപ്പിനെ അനുവദിക്കുക"</string>
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ഫിംഗർപ്രിന്റ് ഹാർഡ്‌വെയർ നിയന്ത്രിക്കുക"</string>
@@ -527,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം പരിഷ്‌ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുക"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"ഇത് നിങ്ങളാണെന്ന് പരിശോധിച്ചുറപ്പിക്കുക"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ബയോമെട്രിക് ഹാർ‌ഡ്‌വെയർ ലഭ്യമല്ല"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"തിരിച്ചറിഞ്ഞില്ല"</string>
@@ -536,7 +527,7 @@
     <string name="biometric_error_device_not_secured" msgid="6583143098363528349">"പിന്നോ പാറ്റേണോ പാസ്‌വേഡോ സജ്ജീകരിച്ചിട്ടില്ല"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"വിരലടയാളം ഭാഗികമായി തിരിച്ചറിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"വിരലടയാളം പ്രോസസ്സ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"വിരലടയാള സെൻസറിന് വൃത്തിയില്ല. അത് ശുചിയാക്കി വീണ്ടും ശ്രമിക്കുക."</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"വിരലടയാള സെൻസറിൽ ചെളിയുണ്ട്. അത് വൃത്തിയാക്കി വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"വിരൽ വളരെ വേഗത്തിൽ നീക്കി. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"വിരൽ വളരെ പതുക്കെ നീക്കി. വീണ്ടും ശ്രമിക്കുക."</string>
   <string-array name="fingerprint_acquired_vendor">
@@ -562,55 +553,36 @@
     <string name="permdesc_manageFace" msgid="8919637120670185330">"ഉപയോഗിക്കാനായി, മുഖത്തിന്റെ ടെംപ്ലേറ്റുകൾ ചേർക്കാനും ഇല്ലാതാക്കാനുമുള്ള രീതികൾ അഭ്യർത്ഥിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"മുഖം തിരിച്ചറിയൽ ഹാർഡ്‌വെയർ ഉപയോഗിക്കുക"</string>
     <string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"പരിശോധിച്ചുറപ്പിക്കലിനായി മുഖം തിരിച്ചറിയൽ ഹാർഡ്‌വെയർ  ഉപയോഗിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
-    <!-- no translation found for face_acquired_insufficient (2767330364802375742) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_bright (5005650874582450967) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_dark (1966194696381394616) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_close (1401011882624272753) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_far (1210969240069012510) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_high (3362395713403348013) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_low (488983581737550912) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_right (941726879175375970) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_left (5873592047381190672) -->
-    <skip />
-    <!-- no translation found for face_acquired_poor_gaze (8471716624377228327) -->
-    <skip />
-    <!-- no translation found for face_acquired_not_detected (4885504661626728809) -->
-    <skip />
-    <!-- no translation found for face_acquired_too_much_motion (3149332171102108851) -->
-    <skip />
+    <string name="face_acquired_insufficient" msgid="2767330364802375742">"കൃത്യ മുഖ ഡാറ്റ എടുക്കാനായില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
+    <string name="face_acquired_too_bright" msgid="5005650874582450967">"വളരെയധികം തെളിച്ചം. സൗമ്യതയേറിയ പ്രകാശം ശ്രമിക്കൂ."</string>
+    <string name="face_acquired_too_dark" msgid="1966194696381394616">"വളരെ ഇരുണ്ടത്. തിളക്കമേറിയ ലൈറ്റിംഗ് പരീക്ഷിക്കുക."</string>
+    <string name="face_acquired_too_close" msgid="1401011882624272753">"ഫോൺ കൂടുതൽ അകലേയ്ക്ക് നീക്കുക."</string>
+    <string name="face_acquired_too_far" msgid="1210969240069012510">"ഫോൺ അടുത്തേക്ക് നീക്കുക."</string>
+    <string name="face_acquired_too_high" msgid="3362395713403348013">"ഫോൺ കൂടുതൽ ഉയരത്തിലേക്ക് നീക്കുക."</string>
+    <string name="face_acquired_too_low" msgid="488983581737550912">"ഫോൺ കൂടുതൽ താഴേക്ക് നീക്കുക."</string>
+    <string name="face_acquired_too_right" msgid="941726879175375970">"ഫോൺ വലത്തോട്ട് നീക്കുക."</string>
+    <string name="face_acquired_too_left" msgid="5873592047381190672">"ഫോൺ ഇടത്തോട്ട് നീക്കുക."</string>
+    <string name="face_acquired_poor_gaze" msgid="8471716624377228327">"തുറന്ന കണ്ണുകളുമായി സ്‌ക്രീനിലേക്ക് നോക്കുക."</string>
+    <string name="face_acquired_not_detected" msgid="4885504661626728809">"നിങ്ങളുടെ മുഖം കാണാനാവുന്നില്ല. ഫോണിലേക്ക് നോക്കൂ."</string>
+    <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"വളരെയധികം ചലനം. ഫോൺ അനക്കാതെ നേരെ പിടിക്കുക."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"നിങ്ങളുടെ മുഖം വീണ്ടും എൻറോൾ ചെയ്യുക."</string>
-    <!-- no translation found for face_acquired_too_different (7663983770123789694) -->
-    <skip />
+    <string name="face_acquired_too_different" msgid="7663983770123789694">"ഇനി മുഖം തിരിച്ചറിയാനാവില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
     <string name="face_acquired_too_similar" msgid="1508776858407646460">"വളരെയധികം സമാനത, നിങ്ങളുടെ പോസ് മാറ്റുക."</string>
-    <!-- no translation found for face_acquired_pan_too_extreme (1852495480382773759) -->
-    <skip />
-    <!-- no translation found for face_acquired_tilt_too_extreme (1290820400317982049) -->
-    <skip />
+    <string name="face_acquired_pan_too_extreme" msgid="1852495480382773759">"അൽപ്പം കൂടി സ്‌ക്രീനിന് നേരെ നോക്കുക."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="1290820400317982049">"അൽപ്പം കൂടി സ്‌ക്രീനിന് നേരെ നോക്കുക."</string>
     <string name="face_acquired_roll_too_extreme" msgid="1444829237745898619">"നിങ്ങളുടെ തല ലംബമായി നേരെയാക്കുക"</string>
-    <!-- no translation found for face_acquired_obscured (5747521031647744553) -->
-    <skip />
-    <!-- no translation found for face_acquired_sensor_dirty (364493868630891300) -->
-    <skip />
+    <string name="face_acquired_obscured" msgid="5747521031647744553">"തലയ്ക്കും ഫോണിനുമിടയിലുള്ള തടസ്സം നീക്കുക."</string>
+    <string name="face_acquired_sensor_dirty" msgid="364493868630891300">"ക്യാമറ വൃത്തിയാക്കുക."</string>
   <string-array name="face_acquired_vendor">
   </string-array>
     <string name="face_error_hw_not_available" msgid="396883585636963908">"മുഖം പരിശോധിക്കാൻ കഴിയില്ല. ഹാർഡ്‌വെയർ ലഭ്യമല്ല."</string>
-    <!-- no translation found for face_error_timeout (2605673935810019129) -->
-    <skip />
+    <string name="face_error_timeout" msgid="2605673935810019129">"മുഖത്തിന്റെ സമയപരിധി കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="face_error_no_space" msgid="2712120617457553825">"പുതിയ മുഖ ഡാറ്റ സംഭരിക്കാനാകില്ല. ആദ്യം പഴയത് ഇല്ലാതാക്കുക."</string>
     <string name="face_error_canceled" msgid="2768146728600802422">"മുഖം തിരിച്ചറിയൽ പ്രവർത്തനം റദ്ദാക്കി"</string>
     <string name="face_error_user_canceled" msgid="9003022830076496163">"മുഖം പരിശോധിച്ചുറപ്പിക്കൽ ഉപയോക്താവ് റദ്ദാക്കി"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="face_error_lockout_permanent" msgid="3485837851962070925">"വളരെയധികം ശ്രമങ്ങൾ. മുഖം തിരിച്ചറിയൽ പ്രവർത്തനരഹിതമാക്കി."</string>
-    <!-- no translation found for face_error_unable_to_process (4940944939691171539) -->
-    <skip />
+    <string name="face_error_unable_to_process" msgid="4940944939691171539">"മുഖം പരിശോധിക്കാൻ കഴിയില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
     <string name="face_error_not_enrolled" msgid="2600952202843125796">"നിങ്ങൾ മുഖം പരിശോധിച്ചുറപ്പിക്കൽ സജ്ജീകരിച്ചില്ല"</string>
     <string name="face_error_hw_not_present" msgid="1317845121210260372">"ഈ ഉപകരണം മുഖം പരിശോധിച്ചുറപ്പിക്കൽ പിന്തുണയ്ക്കുന്നില്ല"</string>
     <string name="face_name_template" msgid="7004562145809595384">"മുഖം <xliff:g id="FACEID">%d</xliff:g>"</string>
@@ -1230,13 +1202,11 @@
     <string name="new_app_action" msgid="6694851182870774403">"<xliff:g id="NEW_APP">%1$s</xliff:g> തുറക്കുക"</string>
     <string name="new_app_description" msgid="5894852887817332322">"<xliff:g id="OLD_APP">%1$s</xliff:g> സംരക്ഷിക്കാതെ അവസാനിപ്പിക്കും"</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> മെമ്മറി പരിധി കവിഞ്ഞു"</string>
-    <!-- no translation found for dump_heap_ready_notification (1162196579925048701) -->
-    <skip />
+    <string name="dump_heap_ready_notification" msgid="1162196579925048701">"<xliff:g id="PROC">%1$s</xliff:g> ഹീപ്പ് ഡംപ് തയ്യാറാണ്"</string>
     <string name="dump_heap_notification_detail" msgid="3993078784053054141">"ഹീപ്പ് ഡംപ് ശേഖരിച്ചു. പങ്കിടാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"ഹീപ്പ് ഡംപ് പങ്കിടണോ?"</string>
-    <!-- no translation found for dump_heap_text (8546022920319781701) -->
-    <skip />
-    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> പ്രോസസ്സ് അതിൻ്റെ മെമ്മറി പരിധിയായ <xliff:g id="SIZE">%2$s</xliff:g> കവിഞ്ഞു. നിങ്ങൾക്ക് പങ്കിടാൻ ഒരു ഹീപ്പ് ഡംപ് ലഭ്യമാണ്. ശ്രദ്ധിക്കുക: പ്രോസസിന് ആക്‌സസ് ചെയ്യാനാകുന്ന, സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട ഏതെങ്കിലും വ്യക്തിഗത വിവരം ഈ ഹീപ്പ് ഡംപിൽ അടങ്ങിയിരിക്കാം, നിങ്ങൾ ടൈപ്പ് ചെയ്‌തിട്ടുള്ള കാര്യങ്ങൾ ഇതിൽ ഉൾപ്പെട്ടിരിക്കാം."</string>
+    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> പ്രോസസിന്, മെമ്മറി പരിധിയായ <xliff:g id="SIZE">%2$s</xliff:g> കവിഞ്ഞു. അതിന്റെ ഡവലപ്പറുമായി പങ്കിടാൻ ഒരു ഹീപ്പ് ഡംപ് നിങ്ങൾക്ക് ലഭ്യമാണ്. ശ്രദ്ധിക്കുക: ഈ ഹീപ്പ് ഡംപിൽ ആപ്പിന് ആക്‌സസുള്ള ഏതെങ്കിലും വ്യക്തിഗത വിവരം അടങ്ങിയിരിക്കാം."</string>
+    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> പ്രോസസ് അതിൻ്റെ മെമ്മറി പരിധിയായ <xliff:g id="SIZE">%2$s</xliff:g> കവിഞ്ഞു. നിങ്ങൾക്ക് പങ്കിടാൻ ഒരു ഹീപ്പ് ഡംപ് ലഭ്യമാണ്. ശ്രദ്ധിക്കുക: പ്രോസസിന് ആക്‌സസ് ചെയ്യാനാകുന്ന, സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട ഏതെങ്കിലും വ്യക്തിഗത വിവരം ഈ ഹീപ്പ് ഡംപിൽ അടങ്ങിയിരിക്കാം, നിങ്ങൾ ടൈപ്പ് ചെയ്‌തിട്ടുള്ള കാര്യങ്ങൾ ഇതിൽ ഉൾപ്പെട്ടിരിക്കാം."</string>
     <string name="dump_heap_ready_text" msgid="1778041771455343067">"നിങ്ങൾക്ക് പങ്കിടാൻ <xliff:g id="PROC">%1$s</xliff:g> എന്നതിൻ്റെ പ്രോസസിൻ്റെ ഒരു ഹീപ്പ് ഡംപ് ലഭ്യമാണ്. ശ്രദ്ധിക്കുക: പ്രോസസിന് ആക്‌സസ് ചെയ്യാനാകുന്ന, സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട ഏതെങ്കിലും വ്യക്തിഗത വിവരം ഈ ഹീപ്പ് ഡംപിൽ അടങ്ങിയിരിക്കാം, നിങ്ങൾ ടൈപ്പ് ചെയ്‌തിട്ടുള്ള കാര്യങ്ങൾ ഇതിൽ ഉൾപ്പെട്ടിരിക്കാം."</string>
     <string name="sendText" msgid="5209874571959469142">"വാചകസന്ദേശത്തിനായി ഒരു പ്രവർത്തനം തിരഞ്ഞെടുക്കുക"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"റിംഗർ വോളിയം"</string>
@@ -1276,10 +1246,8 @@
     <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"എല്ലാ നെറ്റ്‌വർക്കുകളും കാണാൻ ടാപ്പുചെയ്യുക"</string>
     <string name="wifi_available_action_connect" msgid="2635699628459488788">"കണക്റ്റുചെയ്യുക"</string>
     <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"എല്ലാ നെറ്റ്‌വർക്കുകളും"</string>
-    <!-- no translation found for wifi_suggestion_title (9099832833531486167) -->
-    <skip />
-    <!-- no translation found for wifi_suggestion_content (5883181205841582873) -->
-    <skip />
+    <string name="wifi_suggestion_title" msgid="9099832833531486167">"വൈഫൈ നെറ്റ്‌വർക്കുകളിലേക്ക് കണക്റ്റ് ചെയ്യണോ?"</string>
+    <string name="wifi_suggestion_content" msgid="5883181205841582873">"<xliff:g id="NAME">%s</xliff:g> നിർദ്ദേശിച്ചത്"</string>
     <string name="wifi_suggestion_action_allow_app" msgid="3689946344485394085">"ഉവ്വ്"</string>
     <string name="wifi_suggestion_action_disallow_app" msgid="7977918905605931385">"ഇല്ല"</string>
     <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"വൈഫൈ സ്വമേധയാ ഓണാകും"</string>
@@ -1291,14 +1259,11 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <!-- no translation found for wifi_no_internet (5198100389964214865) -->
-    <skip />
+    <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"കണക്‌റ്റ് ചെയ്‌തു"</string>
-    <!-- no translation found for network_partial_connectivity (7774883385494762741) -->
-    <skip />
-    <!-- no translation found for network_partial_connectivity_detailed (1959697814165325217) -->
-    <skip />
+    <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് പരിമിതമായ കണക്റ്റിവിറ്റി ഉണ്ട്"</string>
+    <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ഏതുവിധേനയും കണക്‌റ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="wifi_softap_config_change" msgid="8475911871165857607">"നിങ്ങളുടെ ഹോട്ട്‌സ്‌പോട്ട് ക്രമീകരണത്തിൽ വരുത്തിയ മാറ്റങ്ങൾ"</string>
     <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"നിങ്ങളുടെ ഹോട്ട്‌സ്‌പോട്ട് ബാൻഡ് മാറി."</string>
     <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"നിങ്ങളുടെ മുൻഗണനയനുസരിച്ചുള്ള, 5GHz മാത്രം എന്നത് ഈ ഉപകരണം പിന്തുണയ്ക്കുന്നില്ല. പകരം, 5GHz ബാൻഡ് ലഭ്യമാകുമ്പോൾ അത് ഉപയോഗിക്കും."</string>
@@ -1384,10 +1349,8 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്റ്റ് ചെയ്തു"</string>
     <string name="adb_active_notification_message" msgid="7463062450474107752">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ഡീബഗ്ഗുചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string>
-    <!-- no translation found for test_harness_mode_notification_title (2216359742631914387) -->
-    <skip />
-    <!-- no translation found for test_harness_mode_notification_message (1343197173054407119) -->
-    <skip />
+    <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"പരിശോധനാ സംവിധാനങ്ങൾ മോഡ് പ്രവർത്തനക്ഷമമാക്കി"</string>
+    <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"പരിശോധനാ സംവിധാന മോഡ് പ്രവർത്തനരഹിതമാക്കാൻ ഫാക്‌ടറി പുനഃക്രമീകരണം നിർവഹിക്കുക."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB പോർട്ടിൽ ദ്രാവകമോ പൊടിയോ കണ്ടെത്തി"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB പോർട്ടർ സ്വയമേവ പ്രവർത്തനരഹിതമായി. കൂടുതലറിയാൻ ടാപ്പ് ചെയ്യുക."</string>
     <string name="usb_contaminant_not_detected_title" msgid="4202417484434906086">"USB പോർട്ട് ഇപ്പോൾ സുരക്ഷിതമായി ഉപയോഗിക്കാം"</string>
@@ -1834,10 +1797,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"നിങ്ങളുടെ അഡ്‌മിൻ അപ്‌ഡേറ്റ് ചെയ്യുന്നത്"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"നിങ്ങളുടെ അഡ്‌മിൻ ഇല്ലാതാക്കുന്നത്"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ശരി"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (2108984221113106294) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (6413346684861241431) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ബാറ്ററി ലൈഫ് വികസിപ്പിക്കാൻ പശ്ചാത്തല ആക്‌റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്‌റ്റുകൾ, മറ്റ് ഹൈ പവർ ഫീച്ചറുകൾ എന്നിവയെ ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും. "<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"ബാറ്ററി ലൈഫ് വികസിപ്പിക്കാൻ പശ്ചാത്തല ആക്‌റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്‌റ്റുകൾ, മറ്റ് ഹൈ പവർ ഫീച്ചറുകൾ എന്നിവയെ ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിന്, പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്‌സിനെ ഡാറ്റ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്സസ്സ് ചെയ്യാൻ കഴിയും, എന്നാൽ കുറഞ്ഞ ആവൃത്തിയിലാണിത് നടക്കുക. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദ‍‍‍ർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ഓണാക്കുക"</string>
@@ -2032,22 +1993,14 @@
     <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>
-    <!-- no translation found for battery_saver_notification_channel_name (2083316159716201806) -->
-    <skip />
-    <!-- no translation found for battery_saver_sticky_disabled_notification_title (6376147579378764641) -->
-    <skip />
-    <!-- no translation found for battery_saver_sticky_disabled_notification_summary (8090192609249817945) -->
-    <skip />
-    <!-- no translation found for battery_saver_charged_notification_title (2960978289873161288) -->
-    <skip />
-    <!-- no translation found for battery_saver_charged_notification_title (7555713825806482451) -->
-    <skip />
-    <!-- no translation found for battery_saver_charged_notification_title (5954873381559605660) -->
-    <skip />
-    <!-- no translation found for battery_saver_off_notification_summary (1374222493681267143) -->
-    <skip />
-    <!-- no translation found for battery_saver_off_alternative_notification_summary (4340727818546508436) -->
-    <skip />
+    <string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"ബാറ്ററി ലാഭിക്കൽ"</string>
+    <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"ബാറ്ററി ചാർജ് വീണ്ടും കുറയുന്നത് വരെ ബാറ്ററി ലാഭിക്കൽ പിന്നെയും സജീവമാവുകയില്ല"</string>
+    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"മതിയായ നില വരെ ബാറ്ററി ചാർജായി. വീണ്ടും ബാറ്ററി ചാർജ് കുറയുന്നത് വരെ ബാറ്ററി ലാഭിക്കൽ പിന്നെയും സജീവമാവുകയില്ല."</string>
+    <string name="battery_saver_charged_notification_title" product="default" msgid="2960978289873161288">"ഫോൺ <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> ചാർജായി"</string>
+    <string name="battery_saver_charged_notification_title" product="tablet" msgid="7555713825806482451">"ടാബ്‌ലെറ്റ് <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> ചാർജായി"</string>
+    <string name="battery_saver_charged_notification_title" product="device" msgid="5954873381559605660">"ഉപകരണം <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> ചാർജായി"</string>
+    <string name="battery_saver_off_notification_summary" msgid="1374222493681267143">"ബാറ്ററി ലാഭിക്കൽ ഓഫാണ്. ഫീച്ചറുകൾക്ക് ഇനിമുതൽ നിയന്ത്രണമില്ല."</string>
+    <string name="battery_saver_off_alternative_notification_summary" msgid="4340727818546508436">"ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കി. ഫീച്ചറുകൾക്ക് ഇനിമുതൽ നിയന്ത്രണമില്ല."</string>
     <string name="mime_type_folder" msgid="7111951698626315204">"ഫോള്‍ഡര്‍"</string>
     <string name="mime_type_apk" msgid="5518003630972506900">"Android ആപ്പ്"</string>
     <string name="mime_type_generic" msgid="6833871596845900027">"ഫയൽ"</string>
@@ -2071,6 +2024,5 @@
       <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ഫയലുകൾ</item>
       <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ഫയൽ</item>
     </plurals>
-    <!-- no translation found for chooser_no_direct_share_targets (997970693708458895) -->
-    <skip />
+    <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"നേരിട്ടുള്ള പങ്കിടൽ ലഭ്യമല്ല"</string>
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index c761d97..dfbf579 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"अॅपला तुमच्या फोटो संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"तुमच्या मीडिया संग्रहातून स्थाने वाचा"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"अॅपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"हे तुम्हीच आहात याची पडताळणी करा"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेअर उपलब्ध नाही"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ऑथेंटिकेशन रद्द केले"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ओळखले नाही"</string>
@@ -675,7 +674,7 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"स्टोअर केलेला अ‍ॅप डेटा एंक्रिप्ट केला जाणे आवश्यक आहे."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"कॅमेरे अक्षम करा"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"सर्व डिव्हाइस कॅमेर्‍यांचा वापर प्रतिबंधित करा."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"काही स्क्रीन लॉक वैशिष्‍ट्ये अक्षम करा"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"काही स्क्रीन लॉक वैशिष्‍ट्ये बंद करा"</string>
     <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"काही स्क्रीन लॉक वैशिष्‍ट्यांचा वापर प्रतिबंधित करा."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"घर"</item>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 67f85a7..7762039 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"यसले अनुप्रयोगलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"आफ्नो मिडियाको सङ्ग्रहका स्थानहरू पढ्नुहोस्‌"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"यसले अनुप्रयोगलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"यो तपाईं नै हो भन्ने पुष्टि गर्नुहोस्"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"प्रमाणीकरण रद्द गरियो"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"पहिचान भएन"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 6bbd258..37e452d 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -28,4 +28,6 @@
 
     <!-- The background color of a notification card. -->
     <color name="notification_material_background_color">@color/black</color>
-</resources>
\ No newline at end of file
+
+    <color name="chooser_row_divider">@color/list_divider_color_dark</color>
+</resources>
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index e35b750..98f209d 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -71,4 +71,8 @@
     <style name="ThemeOverlay.DeviceDefault.Accent.DayNight"
            parent="@style/ThemeOverlay.DeviceDefault.Accent" />
 
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
+        <item name="windowLightNavigationBar">false</item>
+    </style>
+
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b13fb8f..4a357b5 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1098,7 +1098,7 @@
     <string name="view_calendar" msgid="979609872939597838">"Weergeven"</string>
     <string name="view_calendar_desc" msgid="5828320291870344584">"Geselecteerde tijd weergeven op de kalender"</string>
     <string name="add_calendar_event" msgid="1953664627192056206">"Plannen"</string>
-    <string name="add_calendar_event_desc" msgid="4326891793260687388">"Evenement plannen voor geselecteerde tijd"</string>
+    <string name="add_calendar_event_desc" msgid="4326891793260687388">"Afspraak plannen voor geselecteerde tijd"</string>
     <string name="view_flight" msgid="7691640491425680214">"Volgen"</string>
     <string name="view_flight_desc" msgid="3876322502674253506">"Geselecteerde vlucht volgen"</string>
     <string name="translate" msgid="9218619809342576858">"Vertalen"</string>
@@ -1209,7 +1209,7 @@
     <string name="dump_heap_system_text" msgid="3236094872980706024">"Het proces <xliff:g id="PROC">%1$s</xliff:g> overschrijdt de geheugenlimiet van <xliff:g id="SIZE">%2$s</xliff:g>. Er is een heap dump beschikbaar die je kunt delen. Let op: Deze heap dump kan gevoelige persoonlijke informatie bevatten waartoe het proces toegang heeft. Dit omvat mogelijk wat je hebt getypt."</string>
     <string name="dump_heap_ready_text" msgid="1778041771455343067">"Er is een heap dump beschikbaar van het proces van <xliff:g id="PROC">%1$s</xliff:g>. Deze kun je delen. Let op: Deze heap dump bevat mogelijk gevoelige persoonlijke informatie waartoe het proces toegang heeft. Dit omvat mogelijk wat je hebt getypt."</string>
     <string name="sendText" msgid="5209874571959469142">"Een actie voor tekst selecteren"</string>
-    <string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string>
+    <string name="volume_ringtone" msgid="6885421406845734650">"Beltoonvolume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Afspelen via Bluetooth"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Stille beltoon ingesteld"</string>
@@ -1220,7 +1220,7 @@
     <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Bluetooth-volume"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Beltoonvolume"</string>
-    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Belvolume"</string>
+    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Gespreksvolume"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolume"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Meldingsvolume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standaardbeltoon"</string>
@@ -1843,7 +1843,7 @@
     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Downtime"</string>
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Doordeweekse avond"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
-    <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Evenement"</string>
+    <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Afspraken"</string>
     <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"Slapen"</string>
     <string name="muted_by" msgid="5942954724562097128">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> dempt sommige geluiden"</string>
     <string name="system_error_wipe_data" msgid="6608165524785354962">"Er is een intern probleem met je apparaat. Het apparaat kan instabiel zijn totdat u het apparaat terugzet naar de fabrieksinstellingen."</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 4611d02..bac464b 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣ ਦਿੰਦੀ ਹੈ।"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨਾ"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"ਪ੍ਰਮਾਣਿਤ ਕਰੋ ਕਿ ਇਹ ਤੁਸੀਂ ਹੀ ਹੋ"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
@@ -1206,7 +1205,7 @@
     <string name="dump_heap_ready_notification" msgid="1162196579925048701">"<xliff:g id="PROC">%1$s</xliff:g> ਹੀਪ ਡੰਪ ਤਿਆਰ ਹੈ"</string>
     <string name="dump_heap_notification_detail" msgid="3993078784053054141">"ਹੀਪ ਡੰਪ ਨੂੰ ਇਕੱਤਰ ਕੀਤਾ ਗਿਆ। ਸਾਂਝਾ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"ਕੀ ਹੀਪ ਡੰਪ ਸ਼ੇਅਰ ਕਰਨਾ ਹੈ?"</string>
-    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> ਪ੍ਰਕਿਰਿਆ ਇਸਦੀ ਮੈਮਰੀ ਸੀਮਾ <xliff:g id="SIZE">%2$s</xliff:g> ਤੋਂ ਵਧ ਗਈ ਹੈ। ਇਸਦੇ ਵਿਕਾਸਕਾਰ ਨਾਲ ਸਾਂਝਾ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਲਈ ਇੱਕ ਹੀਪ ਡੰਪ ਉਪਲਬਧ ਹੈ। ਸਾਵਧਾਨ ਰਹੋ: ਇਸ ਹੀਪ ਡੰਪ ਵਿੱਚ ਤੁਹਾਡੀ ਕੋਈ ਵੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਹੋ ਸਕਦੀ ਹੈ, ਜਿਸ \'ਤੇ ਐਪਲੀਕੇਸ਼ਨ ਦੀ ਪਹੁੰਚ ਹੈ।"</string>
+    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> ਪ੍ਰਕਿਰਿਆ ਇਸਦੀ ਮੈਮੋਰੀ ਸੀਮਾ <xliff:g id="SIZE">%2$s</xliff:g> ਤੋਂ ਵਧ ਗਈ ਹੈ। ਇਸਦੇ ਵਿਕਾਸਕਾਰ ਨਾਲ ਸਾਂਝਾ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਵਾਸਤੇ ਇੱਕ ਹੀਪ ਡੰਪ ਉਪਲਬਧ ਹੈ। ਸਾਵਧਾਨ ਰਹੋ: ਇਸ ਹੀਪ ਡੰਪ ਵਿੱਚ ਤੁਹਾਡੀ ਕੋਈ ਵੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਹੋ ਸਕਦੀ ਹੈ, ਜਿਸ \'ਤੇ ਐਪਲੀਕੇਸ਼ਨ ਦੀ ਪਹੁੰਚ ਹੈ।"</string>
     <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> ਪ੍ਰਕਿਰਿਆ, ਇਸ ਦੀ ਮੈਮੋਰੀ ਸੀਮਾ <xliff:g id="SIZE">%2$s</xliff:g> ਤੋਂ ਵੱਧ ਗਈ ਹੈ। ਸਾਂਝਾ ਕਰਨ ਲਈ ਹੀਪ ਡੰਪ ਤੁਹਾਡੇ ਲਈ ਉਪਲਬਧ ਹੈ। ਸਾਵਧਾਨ ਰਹੋ: ਇਸ ਹੀਪ ਡੰਪ ਵਿੱਚ ਕੋਈ ਵੀ ਸੰਵੇਦਨਸ਼ੀਲ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਜਿਸ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਦੀ ਪਹੁੰਚ ਹੈ, ਜਿਸ ਵਿੱਚ ਸ਼ਾਇਦ ਤੁਹਾਡੇ ਵੱਲੋਂ ਟਾਈਪ ਕੀਤੀਆਂ ਚੀਜ਼ਾਂ ਸ਼ਾਮਲ ਹੋਣ।"</string>
     <string name="dump_heap_ready_text" msgid="1778041771455343067">"ਸਾਂਝਾ ਕਰਨ ਲਈ <xliff:g id="PROC">%1$s</xliff:g> ਦੀ ਪ੍ਰਕਿਰਿਆ ਦਾ ਹੀਪ ਡੰਪ ਤੁਹਾਡੇ ਲਈ ਉਪਲਬਧ ਹੈ। ਸਾਵਧਾਨ ਰਹੋ: ਸ਼ਾਇਦ ਇਸ ਹੀਪ ਡੰਪ ਵਿੱਚ ਕੋਈ ਵੀ ਸੰਵੇਦਨਸ਼ੀਲ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋਵੇ, ਜਿਸ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਦੀ ਪਹੁੰਚ ਹੈ, ਜਿਸ ਵਿੱਚ ਸ਼ਾਇਦ ਤੁਹਾਡੇ ਵੱਲੋਂ ਟਾਈਪ ਕੀਤੀਆਂ ਚੀਜ਼ਾਂ ਸ਼ਾਮਲ ਹੋਣ।"</string>
     <string name="sendText" msgid="5209874571959469142">"ਲਿਖਤ ਲਈ ਕੋਈ ਕਾਰਵਾਈ ਚੁਣੋ"</string>
@@ -1350,7 +1349,7 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
     <string name="adb_active_notification_message" msgid="7463062450474107752">"USB ਡੀਬੱਗਿੰਗ ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ਡੀਬੱਗਿੰਗ ਅਯੋਗ ਬਣਾਉਣ ਲਈ ਚੁਣੋ।"</string>
-    <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ਟੈਸਟ ਹਾਰਨੈੱਸ ਮੋਡ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ਟੈਸਟ ਹਾਰਨੈੱਸ ਮੋਡ ਚਾਲੂ ਹੈ"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ਟੈਸਟ ਹਾਰਨੈੱਸ ਮੋਡ ਬੰਦ ਕਰਨ ਲਈ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਕਰੋ।"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB ਪੋਰਟ ਵਿੱਚ ਪਾਣੀ ਜਾਂ ਧੂੜ-ਮਿੱਟੀ"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ਪੋਰਟ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ। ਹੋਰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 5bf6017..f090ea6 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse sua atividade física?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Registro de chamadas"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"ler e gravar o registro de chamadas telefônicas"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse seu registro de chamadas telefônicas?"</string>
@@ -1213,14 +1213,14 @@
     <string name="volume_music" msgid="5421651157138628171">"Volume da mídia"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduzindo por meio de Bluetooth"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Toque silencioso definido"</string>
-    <string name="volume_call" msgid="3941680041282788711">"Volume na chamada"</string>
-    <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada Bluetooth"</string>
+    <string name="volume_call" msgid="3941680041282788711">"Volume das chamadas"</string>
+    <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume das chamadas por Bluetooth"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string>
     <string name="volume_notification" msgid="2422265656744276715">"Volume da notificação"</string>
     <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Volume de Bluetooth"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Volume do toque"</string>
-    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Volume de chamadas"</string>
+    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Volume das chamadas"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
@@ -1361,7 +1361,7 @@
     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
     <string name="select_input_method" msgid="4653387336791222978">"Selecione o método de entrada"</string>
-    <string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
+    <string name="show_ime" msgid="2506087537466597099">"Mantém o teclado virtual na tela enquanto o teclado físico está ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
@@ -1796,8 +1796,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A \"Economia de bateria\" desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria. "<annotation id="url">"Saiba mais"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"A \"Economia de bateria\" desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria. "<annotation id="url">"Saiba mais"</annotation></string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -1991,15 +1991,15 @@
     <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="dynamic_mode_notification_summary" msgid="2541166298550402690">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
     <string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"Economia de bateria"</string>
-    <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"A \"Economia de bateria\" só será reativada quando a bateria estiver acabando novamente"</string>
-    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"A bateria foi carregada até o nível suficiente. A \"Economia de bateria\" só será reativada quando a bateria estiver acabando novamente."</string>
+    <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"A Economia de bateria só será reativada quando a bateria estiver acabando novamente"</string>
+    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"A bateria foi carregada até o nível suficiente. A Economia de bateria só será reativada quando a bateria estiver acabando novamente."</string>
     <string name="battery_saver_charged_notification_title" product="default" msgid="2960978289873161288">"Smartphone <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> carregado"</string>
     <string name="battery_saver_charged_notification_title" product="tablet" msgid="7555713825806482451">"Tablet <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> carregado"</string>
     <string name="battery_saver_charged_notification_title" product="device" msgid="5954873381559605660">"Dispositivo <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> carregado"</string>
-    <string name="battery_saver_off_notification_summary" msgid="1374222493681267143">"\"Economia de bateria\" desativada. Os recursos não estão mais restritos."</string>
-    <string name="battery_saver_off_alternative_notification_summary" msgid="4340727818546508436">"\"Economia de bateria\" desativada. Os recursos não estão mais restritos."</string>
+    <string name="battery_saver_off_notification_summary" msgid="1374222493681267143">"Economia de bateria desativada. Os recursos não estão mais restritos."</string>
+    <string name="battery_saver_off_alternative_notification_summary" msgid="4340727818546508436">"Economia de bateria desativada. Os recursos não estão mais restritos."</string>
     <string name="mime_type_folder" msgid="7111951698626315204">"Pasta"</string>
     <string name="mime_type_apk" msgid="5518003630972506900">"Aplicativo Android"</string>
     <string name="mime_type_generic" msgid="6833871596845900027">"Arquivo"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 5bf6017..f090ea6 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse sua atividade física?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tire fotos e grave vídeos?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Registro de chamadas"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"ler e gravar o registro de chamadas telefônicas"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Permitir que o app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acesse seu registro de chamadas telefônicas?"</string>
@@ -1213,14 +1213,14 @@
     <string name="volume_music" msgid="5421651157138628171">"Volume da mídia"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduzindo por meio de Bluetooth"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Toque silencioso definido"</string>
-    <string name="volume_call" msgid="3941680041282788711">"Volume na chamada"</string>
-    <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada Bluetooth"</string>
+    <string name="volume_call" msgid="3941680041282788711">"Volume das chamadas"</string>
+    <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume das chamadas por Bluetooth"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string>
     <string name="volume_notification" msgid="2422265656744276715">"Volume da notificação"</string>
     <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Volume de Bluetooth"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Volume do toque"</string>
-    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Volume de chamadas"</string>
+    <string name="volume_icon_description_incall" msgid="8890073218154543397">"Volume das chamadas"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
@@ -1361,7 +1361,7 @@
     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
     <string name="select_input_method" msgid="4653387336791222978">"Selecione o método de entrada"</string>
-    <string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
+    <string name="show_ime" msgid="2506087537466597099">"Mantém o teclado virtual na tela enquanto o teclado físico está ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
@@ -1796,8 +1796,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A \"Economia de bateria\" desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria. "<annotation id="url">"Saiba mais"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"A \"Economia de bateria\" desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria. "<annotation id="url">"Saiba mais"</annotation></string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -1991,15 +1991,15 @@
     <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="dynamic_mode_notification_summary" msgid="2541166298550402690">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
     <string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"Economia de bateria"</string>
-    <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"A \"Economia de bateria\" só será reativada quando a bateria estiver acabando novamente"</string>
-    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"A bateria foi carregada até o nível suficiente. A \"Economia de bateria\" só será reativada quando a bateria estiver acabando novamente."</string>
+    <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"A Economia de bateria só será reativada quando a bateria estiver acabando novamente"</string>
+    <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"A bateria foi carregada até o nível suficiente. A Economia de bateria só será reativada quando a bateria estiver acabando novamente."</string>
     <string name="battery_saver_charged_notification_title" product="default" msgid="2960978289873161288">"Smartphone <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> carregado"</string>
     <string name="battery_saver_charged_notification_title" product="tablet" msgid="7555713825806482451">"Tablet <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> carregado"</string>
     <string name="battery_saver_charged_notification_title" product="device" msgid="5954873381559605660">"Dispositivo <xliff:g id="CHARGE_LEVEL">%1$s</xliff:g> carregado"</string>
-    <string name="battery_saver_off_notification_summary" msgid="1374222493681267143">"\"Economia de bateria\" desativada. Os recursos não estão mais restritos."</string>
-    <string name="battery_saver_off_alternative_notification_summary" msgid="4340727818546508436">"\"Economia de bateria\" desativada. Os recursos não estão mais restritos."</string>
+    <string name="battery_saver_off_notification_summary" msgid="1374222493681267143">"Economia de bateria desativada. Os recursos não estão mais restritos."</string>
+    <string name="battery_saver_off_alternative_notification_summary" msgid="4340727818546508436">"Economia de bateria desativada. Os recursos não estão mais restritos."</string>
     <string name="mime_type_folder" msgid="7111951698626315204">"Pasta"</string>
     <string name="mime_type_apk" msgid="5518003630972506900">"Aplicativo Android"</string>
     <string name="mime_type_generic" msgid="6833871596845900027">"Arquivo"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 2683109..3a942b6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -307,7 +307,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Открыть приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным о физической активности?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"снимать фото и видео"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Разрешить приложению &lt;b&gt;\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"&lt;/b&gt; снимать фото и видео?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; снимать фото и видео?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Список вызовов"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"чтение и запись телефонных звонков"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к списку вызовов?"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 8a91f24..08a9fba 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -407,7 +407,7 @@
     <string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"Ky aplikacion mund të lexojë të gjitha ngjarjet e kalendarit të ruajtura në tabletin tënd dhe të ndajë ose të ruajë të dhënat e kalendarit."</string>
     <string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"Ky aplikacion mund të lexojë të gjitha ngjarjet e kalendarit të ruajtura në televizorin tënd dhe të ndajë ose të ruajë të dhënat e kalendarit."</string>
     <string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"Ky aplikacion mund të lexojë të gjitha ngjarjet e kalendarit të ruajtura në telefonin tënd dhe të ndajë ose të ruajë të dhënat e kalendarit."</string>
-    <string name="permlab_writeCalendar" msgid="8438874755193825647">"shto ose modifiko ngjarjet e kalendarit dhe dërgoju mail të ftuarve, pa dijeninë e zotëruesve"</string>
+    <string name="permlab_writeCalendar" msgid="8438874755193825647">"shto ose modifiko ngjarjet e kalendarit dhe dërgoju email të ftuarve pa dijeninë e zotëruesve"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="1675270619903625982">"Ky aplikacion mund të shtojë, të heqë ose të ndryshojë ngjarjet e kalendarit në tabletin tënd. Ky aplikacion mund të dërgojë mesazhe që mund të duket se vijnë nga zotëruesit e kalendarit ose të ndryshojë ngjarjet pa i njoftuar zotëruesit e tyre."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="9017809326268135866">"Ky aplikacion mund të shtojë, të heqë ose të ndryshojë ngjarjet e kalendarit në televizorin tënd. Ky aplikacion mund të dërgojë mesazhe që mund të duket se vijnë nga zotëruesit e kalendarit ose të ndryshojë ngjarjet pa i njoftuar zotëruesit e tyre."</string>
     <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Ky aplikacion mund të shtojë, të heqë ose të ndryshojë ngjarjet e kalendarit në telefonin tënd. Ky aplikacion mund të dërgojë mesazhe që mund të duket se vijnë nga zotëruesit e kalendarit ose të ndryshojë ngjarjet pa i njoftuar zotëruesit e tyre."</string>
@@ -1153,7 +1153,7 @@
     <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> vazhdon të ndalojë"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> vazhdon të ndalojë"</string>
     <string name="aerr_restart" msgid="7581308074153624475">"Hap përsëri aplikacionin"</string>
-    <string name="aerr_report" msgid="5371800241488400617">"Dërgo komentin"</string>
+    <string name="aerr_report" msgid="5371800241488400617">"Dërgo koment"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Mbyll"</string>
     <string name="aerr_mute" msgid="1974781923723235953">"Vendose në heshtje deri kur të riniset pajisja"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Prit!"</string>
@@ -1924,7 +1924,7 @@
     <string name="time_picker_minute_label" msgid="5168864173796598399">"minutë"</string>
     <string name="time_picker_header_text" msgid="143536825321922567">"Vendos orën"</string>
     <string name="time_picker_input_error" msgid="7574999942502513765">"Fut një kohë të vlefshme"</string>
-    <string name="time_picker_prompt_label" msgid="7588093983899966783">"Shkruaj kohën"</string>
+    <string name="time_picker_prompt_label" msgid="7588093983899966783">"Shkruaj orën"</string>
     <string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Kalo te modaliteti i hyrjes së tekstit për hyrjen e kohës."</string>
     <string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Kalo te modaliteti i orës për hyrjen e kohës."</string>
     <string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Opsionet e plotësimit automatik"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 8ab8b8f..006d6ad 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -302,12 +302,9 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"மைக்ரோஃபோன்"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ஒலிப் பதிவு செய்யலாம்"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ஆடியோவைப் பதிவு செய்ய &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; பயன்பாட்டை அனுமதிக்கவா?"</string>
-    <!-- no translation found for permgrouplab_activityRecognition (1565108047054378642) -->
-    <skip />
-    <!-- no translation found for permgroupdesc_activityRecognition (6949472038320473478) -->
-    <skip />
-    <!-- no translation found for permgrouprequest_activityRecognition (7626438016904799383) -->
-    <skip />
+    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"உடல் செயல்பாடுகள்"</string>
+    <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"உடல் செயல்பாட்டைக் கண்காணிக்கும்"</string>
+    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"உடல் செயல்பாட்டைக் கண்காணிக்க &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"கேமரா"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"படங்கள் மற்றும் வீடியோக்கள் எடுக்கலாம்"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"படங்கள் எடுக்கவும், வீடியோ பதிவு செய்யவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
@@ -530,8 +527,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"உங்களின் படத் தொகுப்பை மாற்ற ஆப்ஸை அனுமதிக்கும்."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"மீடியா தொகுப்பிலிருந்து இடங்களை அறிதல்"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"நீங்கள்தான் என உறுதிசெய்க"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"அங்கீகரிப்பு ரத்தானது"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"அடையாளங்காணபடவில்லை"</string>
@@ -604,25 +600,18 @@
     <skip />
   <string-array name="face_acquired_vendor">
   </string-array>
-    <!-- no translation found for face_error_hw_not_available (396883585636963908) -->
-    <skip />
+    <string name="face_error_hw_not_available" msgid="396883585636963908">"முகத்தைச் சரிபார்க்க இயலவில்லை. வன்பொருள் இல்லை."</string>
     <!-- no translation found for face_error_timeout (2605673935810019129) -->
     <skip />
-    <!-- no translation found for face_error_no_space (2712120617457553825) -->
-    <skip />
-    <!-- no translation found for face_error_canceled (2768146728600802422) -->
-    <skip />
-    <!-- no translation found for face_error_user_canceled (9003022830076496163) -->
-    <skip />
+    <string name="face_error_no_space" msgid="2712120617457553825">"புதிய முகங்களைச் சேர்க்க இயலவில்லை. பழையது ஒன்றை நீக்கவும்."</string>
+    <string name="face_error_canceled" msgid="2768146728600802422">"முக அங்கீகாரச் செயல்பாடு ரத்துசெய்யப்பட்டது"</string>
+    <string name="face_error_user_canceled" msgid="9003022830076496163">"முக அங்கீகாரம் பயனரால் ரத்துசெய்யப்பட்டது"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"பலமுறை முயன்றுவிட்டீர்கள். பிறகு முயலவும்."</string>
-    <!-- no translation found for face_error_lockout_permanent (3485837851962070925) -->
-    <skip />
+    <string name="face_error_lockout_permanent" msgid="3485837851962070925">"பலமுறை முயன்றுவிட்டீர்கள். முக அங்கீகாரம் முடக்கப்பட்டது."</string>
     <!-- no translation found for face_error_unable_to_process (4940944939691171539) -->
     <skip />
-    <!-- no translation found for face_error_not_enrolled (2600952202843125796) -->
-    <skip />
-    <!-- no translation found for face_error_hw_not_present (1317845121210260372) -->
-    <skip />
+    <string name="face_error_not_enrolled" msgid="2600952202843125796">"முக அங்கீகாரத்தை இன்னும் நீங்கள் அமைக்கவில்லை"</string>
+    <string name="face_error_hw_not_present" msgid="1317845121210260372">"இந்தச் சாதனத்தில் முக அங்கீகாரம் ஆதரிக்கப்படவில்லை"</string>
     <string name="face_name_template" msgid="7004562145809595384">"முகம் <xliff:g id="FACEID">%d</xliff:g>"</string>
   <string-array name="face_error_vendor">
   </string-array>
@@ -1246,10 +1235,8 @@
     <string name="dump_heap_title" msgid="5864292264307651673">"ஹீப் டம்பைப் பகிரவா?"</string>
     <!-- no translation found for dump_heap_text (8546022920319781701) -->
     <skip />
-    <!-- no translation found for dump_heap_system_text (3236094872980706024) -->
-    <skip />
-    <!-- no translation found for dump_heap_ready_text (1778041771455343067) -->
-    <skip />
+    <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="SIZE">%2$s</xliff:g> அளவான தனது நினைவக வரம்பை <xliff:g id="PROC">%1$s</xliff:g> செயலாக்கம் மீறியுள்ளது. உங்களுக்கான ஹீப் டம்ப் பகிர்வதற்குக் கிடைக்கிறது. கவனத்திற்கு: நீங்கள் உள்ளிட்டவை உட்பட செயலாக்கத்திற்கு அணுகலுள்ள தனிப்பட்ட தகவல்கள் இந்த ஹீப் டம்பில் இருக்கக்கூடும்"</string>
+    <string name="dump_heap_ready_text" msgid="1778041771455343067">"<xliff:g id="PROC">%1$s</xliff:g> செயலாக்கத்திற்கான ஹீப் டம்ப் நீங்கள் பகிர்வதற்குக் கிடைக்கிறது. கவனத்திற்கு: நீங்கள் உள்ளிட்டவை உட்பட செயலாக்கத்திற்கு அணுகலுள்ள தனிப்பட்ட தகவல்கள் இந்த ஹீப் டம்பில் இருக்கக்கூடும்."</string>
     <string name="sendText" msgid="5209874571959469142">"உரைக்கான செயலைத் தேர்வுசெய்யவும்"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ரிங்கரின் ஒலியளவு"</string>
     <string name="volume_music" msgid="5421651157138628171">"மீடியாவின் ஒலியளவு"</string>
@@ -1656,10 +1643,8 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"மேலோட்ட #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", பாதுகாப்பானது"</string>
-    <!-- no translation found for activity_starter_block_bg_activity_starts_permissive (6995473033438879646) -->
-    <skip />
-    <!-- no translation found for activity_starter_block_bg_activity_starts_enforcing (3317816771072146229) -->
-    <skip />
+    <string name="activity_starter_block_bg_activity_starts_permissive" msgid="6995473033438879646">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>மின் \'பின்னணிச் செயல்பாடுத் தொடக்கம்\' இனிவரும் Q பதிப்புகளில் தடுக்கப்படும். g.co/dev/bgblock என்ற இணைப்பைப் பார்க்கவும்."</string>
+    <string name="activity_starter_block_bg_activity_starts_enforcing" msgid="3317816771072146229">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>மில் \'பின்னணிச் செயல்பாட்டுத் தொடக்கம்\' தடுக்கப்பட்டுள்ளது. g.co/dev/bgblock என்ற இணைப்பைப் பார்க்கவும்."</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"வடிவத்தை மறந்துவிட்டீர்களா"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"தவறான வடிவம்"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"தவறான கடவுச்சொல்"</string>
@@ -1965,7 +1950,7 @@
     <string name="conference_call" msgid="3751093130790472426">"குழு அழைப்பு"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"உதவிக்குறிப்பு"</string>
     <string name="app_category_game" msgid="5431836943981492993">"கேம்ஸ்"</string>
-    <string name="app_category_audio" msgid="1659853108734301647">"இசையும் ஆடியோவும்"</string>
+    <string name="app_category_audio" msgid="1659853108734301647">"இசை &amp; ஆடியோ"</string>
     <string name="app_category_video" msgid="2728726078629384196">"திரைப்படங்களும் வீடியோவும்"</string>
     <string name="app_category_image" msgid="4867854544519846048">"புகைப்படங்களும் படங்களும்"</string>
     <string name="app_category_social" msgid="5842783057834965912">"சமூகமும் தகவல்தொடர்பும்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 9904cfa..1662be7 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -519,8 +519,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"మీ ఫోటో సేకరణను సవరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవండి"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"ఇది మీరేనని ధృవీకరించండి"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"బయోమెట్రిక్ హార్డ్‌వేర్‌ అందుబాటులో లేదు"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ప్రమాణీకరణ రద్దు చేయబడింది"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"గుర్తించలేదు"</string>
@@ -572,7 +571,7 @@
     <string name="face_acquired_pan_too_extreme" msgid="1852495480382773759">"దయచేసి స్క్రీన్ వైపు మరింత సూటిగా చూడండి."</string>
     <string name="face_acquired_tilt_too_extreme" msgid="1290820400317982049">"దయచేసి స్క్రీన్ వైపు మరింత సూటిగా చూడండి."</string>
     <string name="face_acquired_roll_too_extreme" msgid="1444829237745898619">"దయచేసి మీ తలను నిలువుగా, నిటారుగా ఉంచండి."</string>
-    <string name="face_acquired_obscured" msgid="5747521031647744553">"మీ తలకు, ఫోన్‌కు మధ్యన ఖాళీ తగ్గించండి."</string>
+    <string name="face_acquired_obscured" msgid="5747521031647744553">"మీ తలకు, ఫోన్‌కు మధ్యన ఏదీ లేదని నిర్దారించుకోండి."</string>
     <string name="face_acquired_sensor_dirty" msgid="364493868630891300">"దయచేసి కెమెరాను శుభ్రం చేయండి."</string>
   <string-array name="face_acquired_vendor">
   </string-array>
@@ -908,7 +907,7 @@
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nమీరు ఖచ్చితంగా ఈ పేజీ నుండి వెలుపలకు నావిగేట్ చేయాలనుకుంటున్నారా?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"నిర్ధారించండి"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"చిట్కా: దగ్గరకు మరియు దూరానికి జూమ్ చేయడానికి రెండు సార్లు నొక్కండి."</string>
-    <string name="autofill_this_form" msgid="4616758841157816676">"స్వీయ పూరింపు"</string>
+    <string name="autofill_this_form" msgid="4616758841157816676">"ఆటోఫిల్"</string>
     <string name="setup_autofill" msgid="7103495070180590814">"స్వీయ పూరణను సెటప్ చేయండి"</string>
     <string name="autofill_window_title" msgid="4107745526909284887">"<xliff:g id="SERVICENAME">%1$s</xliff:g> ద్వారా స్వీయ పూరింపు చేయండి"</string>
     <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
@@ -1078,7 +1077,7 @@
     <string name="selectTextMode" msgid="1018691815143165326">"వచనాన్ని ఎంచుకోండి"</string>
     <string name="undo" msgid="7905788502491742328">"చర్య రద్దు చేయి"</string>
     <string name="redo" msgid="7759464876566803888">"చర్యను పునరావృతం చేయి"</string>
-    <string name="autofill" msgid="3035779615680565188">"స్వీయ పూరింపు"</string>
+    <string name="autofill" msgid="3035779615680565188">"ఆటోఫిల్"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"వచన ఎంపిక"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"నిఘంటువుకు జోడించు"</string>
     <string name="deleteText" msgid="6979668428458199034">"తొలగించు"</string>
@@ -1118,7 +1117,7 @@
     <string name="dialog_alert_title" msgid="2049658708609043103">"గమనిక"</string>
     <string name="loading" msgid="7933681260296021180">"లోడ్ చేస్తోంది…"</string>
     <string name="capital_on" msgid="1544682755514494298">"ఆన్‌లో ఉంది"</string>
-    <string name="capital_off" msgid="6815870386972805832">"ఆఫ్‌లో ఉంది"</string>
+    <string name="capital_off" msgid="6815870386972805832">"ఆఫ్‌"</string>
     <string name="whichApplication" msgid="4533185947064773386">"దీన్ని ఉపయోగించి చర్యను పూర్తి చేయండి"</string>
     <string name="whichApplicationNamed" msgid="8260158865936942783">"%1$sను ఉపయోగించి చర్యను పూర్తి చేయి"</string>
     <string name="whichApplicationLabel" msgid="7425855495383818784">"చర్యను పూర్తి చేయి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a892632..f47c392 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -526,7 +526,7 @@
     <string name="biometric_error_canceled" msgid="349665227864885880">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string>
     <string name="biometric_error_device_not_secured" msgid="6583143098363528349">"ไม่ได้ตั้ง PIN, รูปแบบ หรือรหัสผ่าน"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ตรวจพบลายนิ้วมือเพียงบางส่วน โปรดลองอีกครั้ง"</string>
-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ไม่สามารถประมวลผลลายนิ้วมือได้ โปรดลองอีกครั้ง"</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ประมวลผลลายนิ้วมือไม่ได้ โปรดลองอีกครั้ง"</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"เซ็นเซอร์ลายนิ้วมือไม่สะอาด โปรดทำความสะอาดและลองอีกครั้ง"</string>
     <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"เคลื่อนนิ้วเร็วเกินไป โปรดลองอีกครั้ง"</string>
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"นิ้วเคลื่อนที่ช้าเกินไป โปรดลองอีกครั้ง"</string>
@@ -661,7 +661,7 @@
     <string name="policylab_wipeData" msgid="3910545446758639713">"ลบข้อมูลทั้งหมด"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ลบข้อมูลของแท็บเล็ตโดยไม่มีการเตือน ด้วยการดำเนินการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ลบข้อมูลของทีวีโดยไม่ต้องมีคำเตือนโดยการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
-    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ลบข้อมูลของโทรศัพท์โดยไม่มีการเตือน ด้วยการดำเนินการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ลบข้อมูลโทรศัพท์โดยไม่มีการเตือน ด้วยการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
     <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ลบข้อมูลผู้ใช้"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"ลบข้อมูลของผู้ใช้นี้ในแท็บเล็ตเครื่องนี้โดยไม่มีการเตือน"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"ลบข้อมูลของผู้ใช้นี้ในทีวีเครื่องนี้โดยไม่มีการเตือน"</string>
@@ -1616,7 +1616,7 @@
       <item quantity="other">ลองอีกครั้งใน <xliff:g id="NUMBER">%d</xliff:g> วินาที</item>
       <item quantity="one">ลองอีกครั้งใน 1 วินาที</item>
     </plurals>
-    <string name="kg_pattern_instructions" msgid="398978611683075868">"วาดรูปแบบของคุณ"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"ลากรูปแบบของคุณ"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ป้อน PIN ของซิม"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"ป้อน PIN"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"ป้อนรหัสผ่าน"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 3c56b01..fa5c479 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına fiziksel aktivitenize erişme izni verilsin mi?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotoğraf çekme ve video kaydetme"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının resim çekmesine ve video kaydı yapmasına izin verilsin mi?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasının fotoğraf çekmesine ve video kaydı yapmasına izin verilsin mi?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Arama kayıtları"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"telefon arama kaydını okuma ve yazma"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Telefon arama kayıtlarınıza erişmek için &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uygulamasına izin verilsin mi?"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index e99eebb..4f42e73d 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -527,8 +527,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ایپ کو آپ کی تصویر کے مجموعے میں ترمیم کی اجازت دیتا ہے۔"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"اپنی میڈيا کے مجموعے سے مقامات پڑھیں"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ایپ کو آپ کی میڈيا کے مجموعے سے مقامات پڑھنے کی اجازت دیتا ہے۔"</string>
-    <!-- no translation found for biometric_dialog_default_title (881952973720613213) -->
-    <skip />
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"توثیق کریں کہ یہ آپ ہیں"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"تصدیق کا عمل منسوخ ہو گیا"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"تسلیم شدہ نہیں ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 123552d..322582d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -140,7 +140,7 @@
     <string name="wfcSpnFormat_wifi" msgid="1892673884655959773">"Wi-Fi"</string>
     <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="1336669776254502831">"Wi-Fi chaqiruv"</string>
     <string name="wfcSpnFormat_vowifi" msgid="1765176406171272629">"VoWi-Fi"</string>
-    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"O‘chiq"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Yoqilmagan"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="7335489823608689868">"Wi-Fi orqali chaqiruv"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="7081742743152286290">"Mobil tarmoq orqali chaqiruv"</string>
     <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Faqat Wi-Fi"</string>
@@ -280,9 +280,9 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun kontaktlaringizga ruxsat berilsinmi?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"shu qurilmaning joylashuvi haqidagi axborotga kirish"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun bu qurilmaning joylashuvi haqidagi axborotdan foydalanishiga ruxsat berilsinmi?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun bu qurilmaning joylashuvi haqidagi axborotdan foydalanishga ruxsat berilsinmi?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"Bu ilovadan foydalanilayotdangina u joylashuv axborotidan foydalana oladi"</string>
-    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasiga bu qurilmaning joylashuv axboroti uchun &lt;b&gt;doimiy&lt;/b&gt; ruxsat berilsinmi?"</string>
+    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun bu qurilmaning joylashuvi haqidagi axborotdan &lt;b&gt;doim&lt;/b&gt; foydalanish ruxsati berilsinmi?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"Ilova hozirda joylashuv axborotidan faqat ilova ishlatilayotgandagina foydala oladi"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Taqvim"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvimingizga kirish"</string>
@@ -981,8 +981,8 @@
     <string name="days" msgid="4774547661021344602">"kun"</string>
     <string name="hour" msgid="2126771916426189481">"soat"</string>
     <string name="hours" msgid="894424005266852993">"soat"</string>
-    <string name="minute" msgid="9148878657703769868">"daq."</string>
-    <string name="minutes" msgid="5646001005827034509">"daq."</string>
+    <string name="minute" msgid="9148878657703769868">"daqiqa"</string>
+    <string name="minutes" msgid="5646001005827034509">"daqiqa"</string>
     <string name="second" msgid="3184235808021478">"sek"</string>
     <string name="seconds" msgid="3161515347216589235">"sek"</string>
     <string name="week" msgid="5617961537173061583">"hafta"</string>
@@ -1836,8 +1836,8 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha (keyingi signal)"</string>
-    <string name="zen_mode_forever" msgid="931849471004038757">"O‘chirmaguningizcha"</string>
-    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"“Bezovta qilinmasin” rejimi o‘chirilmaguncha"</string>
+    <string name="zen_mode_forever" msgid="931849471004038757">"Rejimdan chiqilgunicha"</string>
+    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Bezovta qilinmasin rejimidan chiqilgunicha"</string>
     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Yig‘ish"</string>
     <string name="zen_mode_feature_name" msgid="5254089399895895004">"Bezovta qilinmasin"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 44a7e06..9b7b464 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -280,7 +280,7 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问您的通讯录吗?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"获取此设备的位置信息"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"要允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"要允许<xliff:g id="APP_NAME">%1$s</xliff:g>获取此设备的位置信息吗?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"只有当您使用该应用时,该应用才有权访问位置信息"</string>
     <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"要&lt;b&gt;一律允许&lt;/b&gt;允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问此设备的位置信息吗?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"目前只有当您使用该应用时,该应用才能访问位置信息"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 1e15f18..c633449 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1797,7 +1797,7 @@
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"已由您的管理員刪除"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"好"</string>
     <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"省電模式會關閉或限制背景活動、某些視覺效果以及其他高耗電功能,以延長電池壽命。"<annotation id="url">"瞭解詳情"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"省電模式會關閉或限制背景活動、某些視覺效果以及其他高耗電功能,以延長電池壽命。"</string>
+    <string name="battery_saver_description" msgid="6413346684861241431">"「省電模式」會關閉或限制背景活動、某些視覺效果和其他耗電量高的功能,以延長電池壽命。"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟「數據節省模式」嗎?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9d48fe3..a510424 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2091,6 +2091,40 @@
              Corresponds to {@link android.view.Window#setNavigationBarDividerColor(int)}. -->
         <attr name="navigationBarDividerColor" format="color" />
 
+        <!-- Sets whether the system should ensure that the status bar has enough
+             contrast when a fully transparent background is requested.
+
+             <p>If set to this value, the system will determine whether a scrim is necessary
+             to ensure that the status bar has enough contrast with the contents of
+             this app, and set an appropriate effective bar background color accordingly.
+
+             <p>When the status bar color has a non-zero alpha value, the value of this
+             attribute has no effect.
+
+             <p>If the app does not target at least {@link android.os.Build.VERSION_CODES#Q Q},
+             this attribute is ignored.
+
+             @see android.view.Window#setEnsureStatusBarContrastWhenTransparent 
+             @hide pendingAPI -->
+        <attr name="ensureStatusBarContrastWhenTransparent" format="boolean" />
+
+        <!-- Sets whether the system should ensure that the navigation bar has enough
+             contrast when a fully transparent background is requested.
+
+             <p>If set to this value, the system will determine whether a scrim is necessary
+             to ensure that the navigation bar has enough contrast with the contents of
+             this app, and set an appropriate effective bar background color accordingly.
+
+             <p>When the navigation bar color has a non-zero alpha value, the value of this
+             attribute has no effect.
+
+             <p>If the app does not target at least {@link android.os.Build.VERSION_CODES#Q Q},
+             this attribute is ignored.
+
+             @see android.view.Window#setEnsureNavigationBarContrastWhenTransparent
+             @hide pendingApi -->
+        <attr name="ensureNavigationBarContrastWhenTransparent" format="boolean" />
+
         <!-- The duration, in milliseconds, of the window background fade duration
              when transitioning into or away from an Activity when called with an
              Activity Transition. Corresponds to
@@ -8980,6 +9014,10 @@
         <!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar
                    color. -->
         <attr name="navigationBarColor"/>
+        <!-- @hide From Window.ensureStatusBarContrastWhenTransparent -->
+        <attr name="ensureStatusBarContrastWhenTransparent"/>
+        <!-- @hide From Window.ensureNavigationBarContrastWhenTransparent -->
+        <attr name="ensureNavigationBarContrastWhenTransparent"/>
     </declare-styleable>
 
     <declare-styleable name="Shortcut">
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index e9b1bd3..ef26cd7 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -215,6 +215,5 @@
     <!-- Magnifier -->
     <color name="default_magnifier_color_overlay">#00FFFFFF</color>
 
-    <color name="chooser_row_divider">#1f000000</color>
-
+    <color name="chooser_row_divider">@color/list_divider_color_light</color>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e8cc96c..58afe33 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -313,14 +313,15 @@
          Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
     <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
 
-    <!-- The URL returned by ConnectivityManager#getCaptivePortalServerUrl. The actual returned
-         value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL. This is the default value
-         used if that setting is unset.
+    <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
+         If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+         and if that value is empty, the framework will use a hard-coded default.
          This is *NOT* a URL that will always be used by the system network validation to detect
          captive portals: NetworkMonitor may use different strategies and will not necessarily use
          this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
          instead. -->
-    <string translatable="false" name="config_networkDefaultCaptivePortalServerUrl">http://connectivitycheck.gstatic.com/generate_204</string>
+    <!--suppress CheckTagEmptyBody -->
+    <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
 
     <!-- If the hardware supports specially marking packets that caused a wakeup of the
          main CPU, set this value to the mark used. -->
@@ -1031,6 +1032,9 @@
     <!-- Boolean indicating whether display white balance is supported. -->
     <bool name="config_displayWhiteBalanceAvailable">false</bool>
 
+    <!-- Boolean indicating whether display white balance should be enabled by default. -->
+    <bool name="config_displayWhiteBalanceEnabledDefault">false</bool>
+
     <!-- Minimum color temperature, in Kelvin, supported by display white balance. -->
     <integer name="config_displayWhiteBalanceColorTemperatureMin">4000</integer>
 
@@ -2394,9 +2398,14 @@
     <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
     <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
 
-    <!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
+    <!-- Amount of time in ms the user needs to press the relevant key to bring up the
+         global actions dialog -->
     <integer name="config_globalActionsKeyTimeout">500</integer>
 
+    <!-- Amount of time in ms the user needs to press the relevant keys to trigger the
+         screenshot chord -->
+    <integer name="config_screenshotChordKeyTimeout">500</integer>
+
     <!-- Default width of a vertical scrollbar and height of a horizontal scrollbar.
          Takes effect only if the scrollbar drawables have no intrinsic size. -->
     <dimen name="config_scrollbarSize">4dp</dimen>
@@ -3251,6 +3260,10 @@
     <!-- Controls the size of the back gesture inset. -->
     <dimen name="config_backGestureInset">0dp</dimen>
 
+    <!-- Controls whether the navbar needs a scrim with
+         {@link Window#setEnsureNavigationBarContrastWhenTransparent}. -->
+    <bool name="config_navBarNeedsScrim">true</bool>
+
     <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
          These values are in DPs and will be converted to pixel sizes internally. -->
     <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">16x16</string>
@@ -3345,6 +3358,9 @@
     <!-- True if the device supports system decorations on secondary displays. -->
     <bool name="config_supportsSystemDecorsOnSecondaryDisplays">true</bool>
 
+    <!-- True if the device supports insecure lock screen. -->
+    <bool name="config_supportsInsecureLockScreen">true</bool>
+
     <!-- True if the device requires AppWidgetService even if it does not have
          the PackageManager.FEATURE_APP_WIDGETS feature -->
     <bool name="config_enableAppWidgetService">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c646fef..02cbc2e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -724,6 +724,7 @@
     <dimen name="chooser_edge_margin_thin">16dp</dimen>
     <dimen name="chooser_edge_margin_normal">24dp</dimen>
     <dimen name="chooser_preview_image_font_size">20sp</dimen>
+    <dimen name="chooser_preview_image_border">1dp</dimen>
     <dimen name="chooser_preview_width">-1px</dimen>
     <dimen name="resolver_icon_size">42dp</dimen>
     <dimen name="resolver_badge_size">18dp</dimen>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index a43f752..f22a91f 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -66,9 +66,10 @@
     <dimen name="car_padding_0">4dp</dimen>
     <dimen name="car_padding_1">8dp</dimen>
     <dimen name="car_padding_2">16dp</dimen>
-    <dimen name="car_padding_3">28dp</dimen>
+    <dimen name="car_padding_3">24dp</dimen>
     <dimen name="car_padding_4">32dp</dimen>
     <dimen name="car_padding_5">64dp</dimen>
+    <dimen name="car_padding_6">96dp</dimen>
 
     <!-- Radius -->
     <dimen name="car_radius_1">4dp</dimen>
@@ -121,6 +122,9 @@
     <!-- Dialog button end margin -->
     <dimen name="button_end_margin">@*android:dimen/car_padding_4</dimen>
 
+    <!-- Dialog top padding when there is no title -->
+    <dimen name="dialog_no_title_padding_top">@*android:dimen/car_padding_4</dimen>
+
     <!-- Dialog start margin for text view -->
     <dimen name="text_view_start_margin">@*android:dimen/car_keyline_1</dimen>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6f3adfd..f8a2ac9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -525,7 +525,7 @@
     <!-- label for screenshot item in power menu -->
     <string name="global_action_screenshot">Screenshot</string>
 
-    <!-- Take bug report menu title [CHAR LIMIT=20] -->
+    <!-- Take bug report menu title [CHAR LIMIT=30] -->
     <string name="bugreport_title">Bug report</string>
     <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
     <!-- TODO: remove if not used anymore -->
@@ -1551,25 +1551,25 @@
     <string-array name="face_acquired_vendor">
     </string-array>
 
-    <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=50] -->
+    <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=69] -->
     <string name="face_error_hw_not_available">Can\u2019t verify face. Hardware not available.</string>
     <!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] -->
     <string name="face_error_timeout">Face timeout reached. Try again.</string>
-    <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=60] -->
+    <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=69] -->
     <string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
     <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
     <string name="face_error_canceled">Face operation canceled</string>
-    <!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=50] -->
+    <!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=54] -->
     <string name="face_error_user_canceled">Face authentication canceled by user</string>
     <!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
     <string name="face_error_lockout">Too many attempts. Try again later.</string>
-    <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=60] -->
+    <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=71] -->
     <string name="face_error_lockout_permanent">Too many attempts. Face authentication disabled.</string>
     <!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
     <string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
     <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=52] -->
     <string name="face_error_not_enrolled">You haven\u2019t set up face authentication</string>
-    <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=60] -->
+    <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=61] -->
     <string name="face_error_hw_not_present">Face authentication is not supported on this device</string>
 
     <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 664059a..e9ce6ac 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -391,6 +391,7 @@
   <java-symbol type="bool" name="config_supportsMultiDisplay" />
   <java-symbol type="bool" name="config_noHomeScreen" />
   <java-symbol type="bool" name="config_supportsSystemDecorsOnSecondaryDisplays" />
+  <java-symbol type="bool" name="config_supportsInsecureLockScreen" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
   <java-symbol type="bool" name="config_localDisplaysPrivate" />
@@ -1483,6 +1484,7 @@
   <java-symbol type="drawable" name="ic_settings_print" />
   <java-symbol type="drawable" name="ic_signal_location" />
   <java-symbol type="drawable" name="ic_info_outline_24" />
+  <java-symbol type="drawable" name="ic_qs_ui_mode_night" />
 
   <java-symbol type="drawable" name="stat_notify_mmcc_indication_icn" />
   <java-symbol type="drawable" name="autofilled_highlight"/>
@@ -2010,7 +2012,7 @@
   <java-symbol type="integer" name="config_networkNotifySwitchType" />
   <java-symbol type="array" name="config_networkNotifySwitches" />
   <java-symbol type="integer" name="config_networkAvoidBadWifi" />
-  <java-symbol type="string" name="config_networkDefaultCaptivePortalServerUrl" />
+  <java-symbol type="string" name="config_networkCaptivePortalServerUrl" />
   <java-symbol type="integer" name="config_networkWakeupPacketMark" />
   <java-symbol type="integer" name="config_networkWakeupPacketMask" />
   <java-symbol type="bool" name="config_apfDrop802_3Frames" />
@@ -2227,6 +2229,7 @@
   <java-symbol type="id" name="button_always" />
   <java-symbol type="id" name="button_app_settings" />
   <java-symbol type="integer" name="config_globalActionsKeyTimeout" />
+  <java-symbol type="integer" name="config_screenshotChordKeyTimeout" />
   <java-symbol type="integer" name="config_maxResolverActivityColumns" />
   <java-symbol type="array" name="config_notificationSignalExtractors" />
 
@@ -2776,6 +2779,7 @@
   <java-symbol type="dimen" name="chooser_edge_margin_normal" />
   <java-symbol type="dimen" name="chooser_preview_image_font_size"/>
   <java-symbol type="dimen" name="chooser_preview_width" />
+  <java-symbol type="dimen" name="chooser_preview_image_border"/>
   <java-symbol type="dimen" name="chooser_max_collapsed_height" />
   <java-symbol type="layout" name="chooser_grid" />
   <java-symbol type="layout" name="chooser_grid_preview_text" />
@@ -2789,6 +2793,7 @@
   <java-symbol type="drawable" name="scroll_indicator_material" />
 
   <java-symbol type="layout" name="chooser_row" />
+  <java-symbol type="color" name="chooser_row_divider" />
   <java-symbol type="layout" name="chooser_row_direct_share" />
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
   <java-symbol type="drawable" name="ic_perm_device_info" />
@@ -2845,6 +2850,7 @@
   <java-symbol type="integer" name="config_navBarInteractionMode" />
   <java-symbol type="bool" name="config_navBarCanMove" />
   <java-symbol type="bool" name="config_navBarTapThrough" />
+  <java-symbol type="bool" name="config_navBarNeedsScrim" />
   <java-symbol type="dimen" name="config_backGestureInset" />
   <java-symbol type="color" name="system_bar_background_semi_transparent" />
 
@@ -3147,7 +3153,6 @@
 
   <java-symbol type="bool" name="config_setColorTransformAccelerated" />
   <java-symbol type="bool" name="config_setColorTransformAcceleratedPerLayer" />
-  <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
   <java-symbol type="bool" name="config_nightDisplayAvailable" />
   <java-symbol type="bool" name="config_allowDisablingAssistDisclosure" />
   <java-symbol type="integer" name="config_defaultNightDisplayAutoMode" />
@@ -3159,8 +3164,8 @@
   <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficients" />
   <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
   <java-symbol type="array" name="config_availableColorModes" />
-
   <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
+  <java-symbol type="bool" name="config_displayWhiteBalanceEnabledDefault" />
   <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
   <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMax" />
   <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 9f20ee6..03fb1fc 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1658,7 +1658,7 @@
     <style name="Theme.DeviceDefault.DayNight" parent="Theme.DeviceDefault.Light" />
 
     <!-- Theme used for the intent picker activity. -->
-    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.DayNight">
+    <style name="Theme.DeviceDefault.ResolverCommon" parent="Theme.DeviceDefault.DayNight">
         <item name="windowEnterTransition">@empty</item>
         <item name="windowExitTransition">@empty</item>
         <item name="windowIsTranslucent">true</item>
@@ -1670,6 +1670,12 @@
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+        <item name="navigationBarColor">?attr/colorBackgroundFloating</item>
+        <item name="navigationBarDividerColor">@color/chooser_row_divider</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
+        <item name="windowLightNavigationBar">true</item>
     </style>
 
     <!-- @hide DeviceDefault themes for the autofill FillUi -->
@@ -1719,5 +1725,7 @@
     </style>
 
     <!-- @hide DeviceDefault theme for the DocumentsUI app.  -->
-    <style name="Theme.DeviceDefault.DocumentsUI" parent="Theme.DeviceDefault.DayNight" />
+    <style name="Theme.DeviceDefault.DocumentsUI" parent="Theme.DeviceDefault.DayNight">
+        <item name="actionModeCloseDrawable">@drawable/ic_clear_material</item>
+    </style>
 </resources>
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 447f28e..5c8bced 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -212,15 +212,15 @@
 
     @Test
     public void testRecycleNewIntentItem() {
-        NewIntentItem emptyItem = NewIntentItem.obtain(null, false);
-        NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), true);
+        NewIntentItem emptyItem = NewIntentItem.obtain(null);
+        NewIntentItem item = NewIntentItem.obtain(referrerIntentList());
         assertNotSame(item, emptyItem);
         assertFalse(item.equals(emptyItem));
 
         item.recycle();
         assertEquals(item, emptyItem);
 
-        NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList(), true);
+        NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList());
         assertSame(item, item2);
         assertFalse(item2.equals(emptyItem));
     }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index d117b40..bffeb2a 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -128,7 +128,7 @@
     @Test
     public void testNewIntent() {
         // Write to parcel
-        NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), true /* pause */);
+        NewIntentItem item = NewIntentItem.obtain(referrerIntentList());
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8cc6e37..6550707 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -203,11 +203,7 @@
                     Settings.Global.DATA_ROAMING,
                     Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
                     Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
-                    Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
-                    Settings.Global.DATA_STALL_EVALUATION_TYPE,
-                    Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
                     Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK,
-                    Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
                     Settings.Global.DEBUG_APP,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE,
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 2ef2d04..9520db7 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -20,33 +20,33 @@
            xmlns:xs="http://www.w3.org/2001/XMLSchema">
     <xs:element name="permissions">
         <xs:complexType>
-            <xs:sequence>
-                <xs:element name="group" type="group" maxOccurs="unbounded"/>
-                <xs:element name="permission" type="permission" maxOccurs="unbounded"/>
-                <xs:element name="assign-permission" type="assign-permission" maxOccurs="unbounded"/>
-                <xs:element name="split-permission" type="split-permission" maxOccurs="unbounded"/>
-                <xs:element name="library" type="library" maxOccurs="unbounded"/>
-                <xs:element name="feature" type="feature" maxOccurs="unbounded"/>
-                <xs:element name="unavailable-feature" type="unavailable-feature" maxOccurs="unbounded"/>
-                <xs:element name="allow-in-power-save-except-idle" type="allow-in-power-save-except-idle" maxOccurs="unbounded"/>
-                <xs:element name="allow-in-power-save" type="allow-in-power-save" maxOccurs="unbounded"/>
-                <xs:element name="allow-in-data-usage-save" type="allow-in-data-usage-save" maxOccurs="unbounded"/>
-                <xs:element name="allow-unthrottled-location" type="allow-unthrottled-location" maxOccurs="unbounded"/>
-                <xs:element name="allow-ignore-location-settings" type="allow-ignore-location-settings" maxOccurs="unbounded"/>
-                <xs:element name="allow-implicit-broadcast" type="allow-implicit-broadcast" maxOccurs="unbounded"/>
-                <xs:element name="app-link" type="app-link" maxOccurs="unbounded"/>
-                <xs:element name="system-user-whitelisted-app" type="system-user-whitelisted-app" maxOccurs="unbounded"/>
-                <xs:element name="system-user-blacklisted-app" type="system-user-blacklisted-app" maxOccurs="unbounded"/>
-                <xs:element name="default-enabled-vr-app" type="default-enabled-vr-app" maxOccurs="unbounded"/>
-                <xs:element name="backup-transport-whitelisted-service" type="backup-transport-whitelisted-service" maxOccurs="unbounded"/>
-                <xs:element name="disabled-until-used-preinstalled-carrier-associated-app" type="disabled-until-used-preinstalled-carrier-associated-app" maxOccurs="unbounded"/>
-                <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app" maxOccurs="unbounded"/>
-                <xs:element name="privapp-permissions" type="privapp-permissions" maxOccurs="unbounded"/>
-                <xs:element name="oem-permissions" type="oem-permissions" maxOccurs="unbounded"/>
-                <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app" maxOccurs="unbounded"/>
-                <xs:element name="allow-association" type="allow-association" maxOccurs="unbounded"/>
-                <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted" maxOccurs="unbounded"/>
-            </xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="group" type="group"/>
+                <xs:element name="permission" type="permission"/>
+                <xs:element name="assign-permission" type="assign-permission"/>
+                <xs:element name="split-permission" type="split-permission"/>
+                <xs:element name="library" type="library"/>
+                <xs:element name="feature" type="feature"/>
+                <xs:element name="unavailable-feature" type="unavailable-feature"/>
+                <xs:element name="allow-in-power-save-except-idle" type="allow-in-power-save-except-idle"/>
+                <xs:element name="allow-in-power-save" type="allow-in-power-save"/>
+                <xs:element name="allow-in-data-usage-save" type="allow-in-data-usage-save"/>
+                <xs:element name="allow-unthrottled-location" type="allow-unthrottled-location"/>
+                <xs:element name="allow-ignore-location-settings" type="allow-ignore-location-settings"/>
+                <xs:element name="allow-implicit-broadcast" type="allow-implicit-broadcast"/>
+                <xs:element name="app-link" type="app-link"/>
+                <xs:element name="system-user-whitelisted-app" type="system-user-whitelisted-app"/>
+                <xs:element name="system-user-blacklisted-app" type="system-user-blacklisted-app"/>
+                <xs:element name="default-enabled-vr-app" type="default-enabled-vr-app"/>
+                <xs:element name="backup-transport-whitelisted-service" type="backup-transport-whitelisted-service"/>
+                <xs:element name="disabled-until-used-preinstalled-carrier-associated-app" type="disabled-until-used-preinstalled-carrier-associated-app"/>
+                <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app"/>
+                <xs:element name="privapp-permissions" type="privapp-permissions"/>
+                <xs:element name="oem-permissions" type="oem-permissions"/>
+                <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/>
+                <xs:element name="allow-association" type="allow-association"/>
+                <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/>
+            </xs:choice>
         </xs:complexType>
     </xs:element>
     <xs:complexType name="group">
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index c25bc14..771c1df 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -153,31 +153,31 @@
 
   public class Permissions {
     ctor public Permissions();
-    method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation();
-    method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
-    method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast();
-    method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave();
-    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave();
-    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
-    method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation();
-    method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink();
-    method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission();
-    method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
-    method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted();
-    method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp();
-    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
-    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
-    method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature();
-    method public java.util.List<com.android.xml.permission.configfile.Group> getGroup();
-    method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
-    method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary();
-    method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions();
-    method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission();
-    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions();
-    method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission();
-    method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
-    method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
-    method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature();
+    method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink_optional();
+    method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission_optional();
+    method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService_optional();
+    method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted_optional();
+    method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp_optional();
+    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp_optional();
+    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp_optional();
+    method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature_optional();
+    method public java.util.List<com.android.xml.permission.configfile.Group> getGroup_optional();
+    method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp_optional();
+    method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary_optional();
+    method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions_optional();
+    method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission_optional();
+    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions_optional();
+    method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission_optional();
+    method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp_optional();
+    method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp_optional();
+    method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature_optional();
   }
 
   public class PrivappPermissions {
diff --git a/core/xsd/vts/Android.bp b/core/xsd/vts/Android.bp
new file mode 100644
index 0000000..9cf68c1
--- /dev/null
+++ b/core/xsd/vts/Android.bp
@@ -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.
+//
+
+cc_test {
+    name: "vts_permission_validate_test",
+    srcs: [
+        "ValidatePermission.cpp"
+    ],
+    static_libs: [
+        "android.hardware.audio.common.test.utility",
+        "libxml2",
+    ],
+    shared_libs: [
+        "liblog",
+	"libbase",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/core/xsd/vts/Android.mk b/core/xsd/vts/Android.mk
new file mode 100644
index 0000000..a5754a4
--- /dev/null
+++ b/core/xsd/vts/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsValidatePermission
+include test/vts/tools/build/Android.host_config.mk
diff --git a/core/xsd/vts/AndroidTest.xml b/core/xsd/vts/AndroidTest.xml
new file mode 100644
index 0000000..e5cc9a0
--- /dev/null
+++ b/core/xsd/vts/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS VtsValidatePermission.">
+    <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HostDrivenTest.push"/>
+        <option name="push" value="DATA/etc/permission.xsd->/data/local/tmp/permission.xsd"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="VtsValidatePermission"/>
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_permission_validate_test/vts_permission_validate_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_permission_validate_test/vts_permission_validate_test" />
+        <option name="binary-test-type" value="gtest"/>
+        <option name="test-timeout" value="30s"/>
+    </test>
+</configuration>
diff --git a/core/xsd/vts/ValidatePermission.cpp b/core/xsd/vts/ValidatePermission.cpp
new file mode 100644
index 0000000..3499689
--- /dev/null
+++ b/core/xsd/vts/ValidatePermission.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include <dirent.h>
+#include <regex>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string>
+
+#include "android-base/logging.h"
+#include "utility/ValidateXml.h"
+
+static void get_files_in_dirs(const char* dir_path, std::vector<std::string>& files) {
+    DIR* d;
+    struct dirent* de;
+
+    d = opendir(dir_path);
+    if (d == nullptr) {
+        return;
+    }
+
+    while ((de = readdir(d))) {
+        if (de->d_type != DT_REG) {
+            continue;
+        }
+        if (std::regex_match(de->d_name, std::regex("(.*)(.xml)"))) {
+            files.push_back(de->d_name);
+        }
+    }
+    closedir(d);
+}
+
+TEST(CheckConfig, permission) {
+    RecordProperty("description",
+                   "Verify that the permission file "
+                   "is valid according to the schema");
+
+    const char* location = "/vendor/etc/permissions";
+
+    std::vector<std::string> files;
+    get_files_in_dirs(location, files);
+
+    for (std::string file_name : files) {
+        EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(file_name.c_str(), {location},
+                                                "/data/local/tmp/permission.xsd");
+    }
+}
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 3562a8f..a4337cc8 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -35,6 +35,7 @@
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MASTER_CLEAR"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+        <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ed198e6..e4a93e7 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -309,6 +309,7 @@
         <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
         <permission name="android.permission.SET_WALLPAPER" />
         <permission name="android.permission.SET_WALLPAPER_COMPONENT" />
+        <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 170dec2..07f81c1 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -763,6 +763,18 @@
     }
 
     /**
+     * Utility method to create a hardware backed bitmap using the graphics buffer.
+     * @hide
+     */
+    @Nullable
+    public static Bitmap wrapHardwareBuffer(@NonNull GraphicBuffer graphicBuffer,
+            @Nullable ColorSpace colorSpace) {
+        try (HardwareBuffer hb = HardwareBuffer.createFromGraphicBuffer(graphicBuffer)) {
+            return wrapHardwareBuffer(hb, colorSpace);
+        }
+    }
+
+    /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
      * specified width and height are the same as the current width and height of
      * the source bitmap, the source bitmap is returned and no new bitmap is
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index c4df274..bd6ce7e 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -22,7 +22,8 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
-import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricPrompt;
 import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.text.TextUtils;
@@ -670,9 +671,9 @@
     }
 
     /**
-     * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
-     * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
-     * require fingerprint user authentication for every use.
+     * Returns {@code true} if the key is irreversibly invalidated when a new biometric is
+     * enrolled or all enrolled biometrics are removed. This has effect only for keys that
+     * require biometric user authentication for every use.
      *
      * @see #isUserAuthenticationRequired()
      * @see #getUserAuthenticationValidityDurationSeconds()
@@ -1098,19 +1099,19 @@
          * <li>The key can only be generated if secure lock screen is set up (see
          * {@link KeyguardManager#isDeviceSecure()}). Additionally, if the key requires that user
          * authentication takes place for every use of the key (see
-         * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one fingerprint
-         * must be enrolled (see {@link FingerprintManager#hasEnrolledFingerprints()}).</li>
+         * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one biometric
+         * must be enrolled (see {@link BiometricManager#canAuthenticate()}).</li>
          * <li>The use of the key must be authorized by the user by authenticating to this Android
          * device using a subset of their secure lock screen credentials such as
-         * password/PIN/pattern or fingerprint.
+         * password/PIN/pattern or biometric.
          * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
          * information</a>.
          * <li>The key will become <em>irreversibly invalidated</em> once the secure lock screen is
          * disabled (reconfigured to None, Swipe or other mode which does not authenticate the user)
          * or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
          * Additionally, if the key requires that user authentication takes place for every use of
-         * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
-         * no more fingerprints are enrolled, unless {@link
+         * the key, it is also irreversibly invalidated once a new biometric is enrolled or once\
+         * no more biometrics are enrolled, unless {@link
          * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
          * enrollment. Attempts to initialize cryptographic operations using such keys will throw
          * {@link KeyPermanentlyInvalidatedException}.</li>
@@ -1121,7 +1122,7 @@
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          * @see KeyguardManager#isDeviceSecure()
-         * @see FingerprintManager#hasEnrolledFingerprints()
+         * @see BiometricManager#canAuthenticate()
          */
         @NonNull
         public Builder setUserAuthenticationRequired(boolean required) {
@@ -1161,10 +1162,10 @@
          * the key.
          *
          * <p>Cryptographic operations involving keys which require user authentication to take
-         * place for every operation can only use fingerprint authentication. This is achieved by
+         * place for every operation can only use biometric authentication. This is achieved by
          * initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac})
-         * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking
-         * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with
+         * with the key, wrapping it into a {@link BiometricPrompt.CryptoObject}, invoking
+         * {@code BiometricPrompt.authenticate} with {@code CryptoObject}, and proceeding with
          * the cryptographic operation only if the authentication flow succeeds.
          *
          * <p>Cryptographic operations involving keys which are authorized to be used for a duration
@@ -1183,8 +1184,8 @@
          *        for every use of the key.
          *
          * @see #setUserAuthenticationRequired(boolean)
-         * @see FingerprintManager
-         * @see FingerprintManager.CryptoObject
+         * @see BiometricPrompt
+         * @see BiometricPrompt.CryptoObject
          * @see KeyguardManager
          */
         @NonNull
@@ -1286,20 +1287,20 @@
         }
 
         /**
-         * Sets whether this key should be invalidated on fingerprint enrollment.  This
+         * Sets whether this key should be invalidated on biometric enrollment.  This
          * applies only to keys which require user authentication (see {@link
          * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
          * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
-         * valid for fingerprint authentication only.
+         * valid for biometric authentication only.
          *
          * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
-         * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
-         * fingerprint is enrolled, or when all existing fingerprints are deleted.  That may be
+         * biometric authentication only are <em>irreversibly invalidated</em> when a new
+         * biometric is enrolled, or when all existing biometrics are deleted.  That may be
          * changed by calling this method with {@code invalidateKey} set to {@code false}.
          *
-         * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+         * <p>Invalidating keys on enrollment of a new biometric or unenrollment of all biometrics
          * improves security by ensuring that an unauthorized person who obtains the password can't
-         * gain the use of fingerprint-authenticated keys by enrolling their own finger.  However,
+         * gain the use of biometric-authenticated keys by enrolling their own biometric.  However,
          * invalidating keys makes key-dependent operations impossible, requiring some fallback
          * procedure to authenticate the user and set up a new key.
          */
@@ -1322,7 +1323,7 @@
          * Sets whether the keystore requires the screen to be unlocked before allowing decryption
          * using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
          * key while the screen is locked will fail. A locked device requires a PIN, password,
-         * fingerprint, or other trusted factor to access. While the screen is locked, the key can
+         * biometric, or other trusted factor to access. While the screen is locked, the key can
          * still be used for encryption or signature verification.
          */
         @NonNull
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 3357fdf..26181a6 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -21,12 +21,13 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.app.KeyguardManager;
-import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricPrompt;
 import android.security.GateKeeper;
 
 import java.security.Key;
-import java.security.Signature;
 import java.security.KeyStore.ProtectionParameter;
+import java.security.Signature;
 import java.security.cert.Certificate;
 import java.util.Date;
 
@@ -479,9 +480,9 @@
     }
 
     /**
-     * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
-     * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
-     * require fingerprint user authentication for every use.
+     * Returns {@code true} if the key is irreversibly invalidated when a new biometric is
+     * enrolled or all enrolled biometrics are removed. This has effect only for keys that
+     * require biometric user authentication for every use.
      *
      * @see #isUserAuthenticationRequired()
      * @see #getUserAuthenticationValidityDurationSeconds()
@@ -496,7 +497,7 @@
      *
      * Normally an authentication-bound key is tied to the secure user id of the current user
      * (either the root SID from GateKeeper for auth-bound keys with a timeout, or the authenticator
-     * id of the current fingerprint set for keys requiring explicit fingerprint authorization).
+     * id of the current biometric set for keys requiring explicit biometric authorization).
      * If this parameter is set (this method returning non-zero value), the key should be tied to
      * the specified secure user id, overriding the logic above.
      *
@@ -762,19 +763,19 @@
          * <li>The key can only be import if secure lock screen is set up (see
          * {@link KeyguardManager#isDeviceSecure()}). Additionally, if the key requires that user
          * authentication takes place for every use of the key (see
-         * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one fingerprint
-         * must be enrolled (see {@link FingerprintManager#hasEnrolledFingerprints()}).</li>
+         * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one biometric
+         * must be enrolled (see {@link BiometricManager#canAuthenticate()}).</li>
          * <li>The use of the key must be authorized by the user by authenticating to this Android
          * device using a subset of their secure lock screen credentials such as
-         * password/PIN/pattern or fingerprint.
+         * password/PIN/pattern or biometric.
          * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
          * information</a>.
          * <li>The key will become <em>irreversibly invalidated</em> once the secure lock screen is
          * disabled (reconfigured to None, Swipe or other mode which does not authenticate the user)
          * or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
          * Additionally, if the key requires that user authentication takes place for every use of
-         * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
-         * no more fingerprints are enrolled, unless {@link
+         * the key, it is also irreversibly invalidated once a new biometric is enrolled or once\
+         * no more biometrics are enrolled, unless {@link
          * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
          * enrollment. Attempts to initialize cryptographic operations using such keys will throw
          * {@link KeyPermanentlyInvalidatedException}.</li> </ul>
@@ -784,7 +785,7 @@
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          * @see KeyguardManager#isDeviceSecure()
-         * @see FingerprintManager#hasEnrolledFingerprints()
+         * @see BiometricManager#canAuthenticate()
          */
         @NonNull
         public Builder setUserAuthenticationRequired(boolean required) {
@@ -824,10 +825,10 @@
          * the key.
          *
          * <p>Cryptographic operations involving keys which require user authentication to take
-         * place for every operation can only use fingerprint authentication. This is achieved by
+         * place for every operation can only use biometric authentication. This is achieved by
          * initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac})
-         * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking
-         * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with
+         * with the key, wrapping it into a {@link BiometricPrompt.CryptoObject}, invoking
+         * {@code BiometricPrompt.authenticate} with {@code CryptoObject}, and proceeding with
          * the cryptographic operation only if the authentication flow succeeds.
          *
          * <p>Cryptographic operations involving keys which are authorized to be used for a duration
@@ -846,8 +847,8 @@
          *        for every use of the key.
          *
          * @see #setUserAuthenticationRequired(boolean)
-         * @see FingerprintManager
-         * @see FingerprintManager.CryptoObject
+         * @see BiometricPrompt
+         * @see BiometricPrompt.CryptoObject
          * @see KeyguardManager
          */
         @NonNull
@@ -902,20 +903,20 @@
         }
 
         /**
-         * Sets whether this key should be invalidated on fingerprint enrollment.  This
+         * Sets whether this key should be invalidated on biometric enrollment.  This
          * applies only to keys which require user authentication (see {@link
          * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
          * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
-         * valid for fingerprint authentication only.
+         * valid for biometric authentication only.
          *
          * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
-         * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
-         * fingerprint is enrolled, or when all existing fingerprints are deleted.  That may be
+         * biometric authentication only are <em>irreversibly invalidated</em> when a new
+         * biometric is enrolled, or when all existing biometrics are deleted.  That may be
          * changed by calling this method with {@code invalidateKey} set to {@code false}.
          *
-         * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+         * <p>Invalidating keys on enrollment of a new biometric or unenrollment of all biometrics
          * improves security by ensuring that an unauthorized person who obtains the password can't
-         * gain the use of fingerprint-authenticated keys by enrolling their own finger.  However,
+         * gain the use of biometric-authenticated keys by enrolling their own biometric.  However,
          * invalidating keys makes key-dependent operations impossible, requiring some fallback
          * procedure to authenticate the user and set up a new key.
          */
@@ -930,7 +931,7 @@
          *
          * Normally an authentication-bound key is tied to the secure user id of the current user
          * (either the root SID from GateKeeper for auth-bound keys with a timeout, or the
-         * authenticator id of the current fingerprint set for keys requiring explicit fingerprint
+         * authenticator id of the current biometric set for keys requiring explicit biometric
          * authorization). If this parameter is set (this method returning non-zero value), the key
          * should be tied to the specified secure user id, overriding the logic above.
          *
@@ -964,7 +965,7 @@
          * Sets whether the keystore requires the screen to be unlocked before allowing decryption
          * using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
          * key while the screen is locked will fail. A locked device requires a PIN, password,
-         * fingerprint, or other trusted factor to access. While the screen is locked, the key can
+         * biometric, or other trusted factor to access. While the screen is locked, the key can
          * still be used for encryption or signature verification.
          */
         @NonNull
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 36f540c..be78b69 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -266,49 +266,48 @@
         vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
     }
 
-    if (nullptr != vkManager.mGetPhysicalDeviceImageFormatProperties2) {
-        VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
-        externalImageFormatInfo.sType =
-                VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
-        externalImageFormatInfo.pNext = nullptr;
-        externalImageFormatInfo.handleType =
-                VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+    LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2,
+                        "vkGetPhysicalDeviceImageFormatProperties2 is missing");
+    VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
+    externalImageFormatInfo.sType =
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
+    externalImageFormatInfo.pNext = nullptr;
+    externalImageFormatInfo.handleType =
+            VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
 
-        VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
-        imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
-        imageFormatInfo.pNext = &externalImageFormatInfo;
-        imageFormatInfo.format = vkPixelFormat;
-        imageFormatInfo.type = VK_IMAGE_TYPE_2D;
-        imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
-        imageFormatInfo.usage = usageFlags;
-        imageFormatInfo.flags = 0;
+    VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
+    imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+    imageFormatInfo.pNext = &externalImageFormatInfo;
+    imageFormatInfo.format = vkPixelFormat;
+    imageFormatInfo.type = VK_IMAGE_TYPE_2D;
+    imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+    imageFormatInfo.usage = usageFlags;
+    imageFormatInfo.flags = 0;
 
-        VkAndroidHardwareBufferUsageANDROID hwbUsage;
-        hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
-        hwbUsage.pNext = nullptr;
+    VkAndroidHardwareBufferUsageANDROID hwbUsage;
+    hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
+    hwbUsage.pNext = nullptr;
 
-        VkImageFormatProperties2 imgFormProps;
-        imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
-        imgFormProps.pNext = &hwbUsage;
+    VkImageFormatProperties2 imgFormProps;
+    imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+    imgFormProps.pNext = &hwbUsage;
 
-        res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice,
-                                                                 &imageFormatInfo, &imgFormProps);
-        if (VK_SUCCESS != res) {
-            ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
-            return nullptr;
-        }
-
-        windowInfo.windowUsageFlags = hwbUsage.androidHardwareBufferUsage;
-        if (vkManager.isQualcomm()) {
-            windowInfo.windowUsageFlags =
-                    windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0;
-        }
-
-    } else {
-        ALOGE("VulkanSurface::Create() vkmGetPhysicalDeviceImageFormatProperties2 is missing");
+    res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice,
+                                                             &imageFormatInfo, &imgFormProps);
+    if (VK_SUCCESS != res) {
+        ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2");
         return nullptr;
     }
 
+    uint64_t consumerUsage;
+    native_window_get_consumer_usage(window, &consumerUsage);
+    windowInfo.windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
+
+    if (vkManager.isQualcomm()) {
+        windowInfo.windowUsageFlags =
+                windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0;
+    }
+
     /*
      * Now we attempt to modify the window!
      */
diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp
index c564ed6..70a5f5a 100644
--- a/libs/hwui/tests/unit/CommonPoolTests.cpp
+++ b/libs/hwui/tests/unit/CommonPoolTests.cpp
@@ -135,4 +135,48 @@
     for (auto& f : futures) {
         f.get();
     }
+}
+
+class ObjectTracker {
+    static std::atomic_int sGlobalCount;
+
+public:
+    ObjectTracker() {
+        sGlobalCount++;
+    }
+    ObjectTracker(const ObjectTracker&) {
+        sGlobalCount++;
+    }
+    ObjectTracker(ObjectTracker&&) {
+        sGlobalCount++;
+    }
+    ~ObjectTracker() {
+        sGlobalCount--;
+    }
+
+    static int count() { return sGlobalCount.load(); }
+};
+
+std::atomic_int ObjectTracker::sGlobalCount{0};
+
+TEST(CommonPool, asyncLifecycleCheck) {
+    ASSERT_EQ(0, ObjectTracker::count());
+    {
+        ObjectTracker obj;
+        ASSERT_EQ(1, ObjectTracker::count());
+        EXPECT_LT(1, CommonPool::async([obj] { return ObjectTracker::count(); }).get());
+    }
+    CommonPool::waitForIdle();
+    ASSERT_EQ(0, ObjectTracker::count());
+}
+
+TEST(CommonPool, syncLifecycleCheck) {
+    ASSERT_EQ(0, ObjectTracker::count());
+    {
+        ObjectTracker obj;
+        ASSERT_EQ(1, ObjectTracker::count());
+        EXPECT_LT(1, CommonPool::runSync([obj] { return ObjectTracker::count(); }));
+    }
+    CommonPool::waitForIdle();
+    ASSERT_EQ(0, ObjectTracker::count());
 }
\ No newline at end of file
diff --git a/libs/hwui/thread/CommonPool.cpp b/libs/hwui/thread/CommonPool.cpp
index 7f94a15..d011bdf 100644
--- a/libs/hwui/thread/CommonPool.cpp
+++ b/libs/hwui/thread/CommonPool.cpp
@@ -49,9 +49,13 @@
     }
 }
 
-void CommonPool::post(Task&& task) {
+CommonPool& CommonPool::instance() {
     static CommonPool pool;
-    pool.enqueue(std::move(task));
+    return pool;
+}
+
+void CommonPool::post(Task&& task) {
+    instance().enqueue(std::move(task));
 }
 
 void CommonPool::enqueue(Task&& task) {
@@ -86,5 +90,18 @@
     }
 }
 
+void CommonPool::waitForIdle() {
+    instance().doWaitForIdle();
+}
+
+void CommonPool::doWaitForIdle() {
+    std::unique_lock lock(mLock);
+    while (mWaitingThreads != THREAD_COUNT) {
+        lock.unlock();
+        usleep(100);
+        lock.lock();
+    }
+}
+
 }  // namespace uirenderer
 }  // namespace android
\ No newline at end of file
diff --git a/libs/hwui/thread/CommonPool.h b/libs/hwui/thread/CommonPool.h
index aef2990..7603eee 100644
--- a/libs/hwui/thread/CommonPool.h
+++ b/libs/hwui/thread/CommonPool.h
@@ -57,11 +57,13 @@
         mHead = newHead;
     }
 
-    constexpr T&& pop() {
+    constexpr T pop() {
         LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
         int index = mTail;
         mTail = (mTail + 1) % SIZE;
-        return std::move(mBuffer[index]);
+        T ret = std::move(mBuffer[index]);
+        mBuffer[index] = nullptr;
+        return ret;
     }
 
 private:
@@ -95,11 +97,17 @@
         return task.get_future().get();
     };
 
+    // For testing purposes only, blocks until all worker threads are parked.
+    static void waitForIdle();
+
 private:
+    static CommonPool& instance();
+
     CommonPool();
     ~CommonPool() {}
 
     void enqueue(Task&&);
+    void doWaitForIdle();
 
     void workerLoop();
 
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index d14116f..39740bd 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -60,6 +60,9 @@
 }
 
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
+    if (dataspace == HAL_DATASPACE_UNKNOWN) {
+        return SkColorSpace::MakeSRGB();
+    }
 
     skcms_Matrix3x3 gamut;
     switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
diff --git a/media/Android.bp b/media/Android.bp
index 3480181..8746046 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -24,6 +24,10 @@
         "mediaplayer2-protos",
     ],
 
+    permitted_packages: [
+        "android.media",
+    ],
+
     installable: true,
 
     // Make sure that the implementaion only relies on SDK or system APIs.
diff --git a/media/OWNERS b/media/OWNERS
index 72c8952..a33a990 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,3 +1,4 @@
+andrewlewis@google.com
 chz@google.com
 dwkang@google.com
 elaurent@google.com
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 87035da..72c18f6 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -31,6 +31,7 @@
 import android.media.MediaPlayer2.DrmInfo;
 import android.media.MediaPlayer2Proto.PlayerMessage;
 import android.media.MediaPlayer2Proto.Value;
+import android.media.protobuf.InvalidProtocolBufferException;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -46,7 +47,6 @@
 import android.view.SurfaceHolder;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.media.protobuf.InvalidProtocolBufferException;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -546,7 +546,7 @@
             @Override
             void process() {
                 if (getState() == PLAYER_STATE_PLAYING) {
-                    pause();
+                    native_pause();
                 }
                 playNextDataSource();
             }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 3a33678..9d4bce7 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -893,7 +893,7 @@
          * @param muted true to force muting haptic channels.
          * @return the same Builder instance.
          */
-        public Builder setMuteHapticChannels(boolean muted) {
+        public @NonNull Builder setHapticChannelsMuted(boolean muted) {
             mMuteHapticChannels = muted;
             return this;
         }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 325e227..790e189 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -25,7 +25,6 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -1662,7 +1661,7 @@
      * a better solution.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 112561552)
+    @UnsupportedAppUsage(trackingBug = 130237544)
     public int getLatency() {
         return native_get_latency();
     }
diff --git a/media/proto/jarjar-rules.txt b/media/proto/jarjar-rules.txt
index bfb0b27..e73f86d 100644
--- a/media/proto/jarjar-rules.txt
+++ b/media/proto/jarjar-rules.txt
@@ -1,2 +1,2 @@
-rule com.google.protobuf.** com.android.media.protobuf.@1
+rule com.google.protobuf.** android.media.protobuf.@1
 
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index 302cbd1..9791da6 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -250,7 +250,8 @@
                 minikin::U16StringPiece(text, textLength),
                 matcher->mFontStyle,
                 matcher->mLocaleListId,
-                static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant));
+                static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant),
+                1  /* maxRun */);
 
     const minikin::Font* font = runs[0].fakedFont.font;
     std::unique_ptr<AFont> result = std::make_unique<AFont>();
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index a528636..355bdd8 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -18,7 +18,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.captiveportallogin"
-    android:versionCode="200000000"
+    android:versionCode="210000000"
     android:versionName="Q-initial">
 
     <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
index 0a20eaa..a371a1d8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -21,6 +21,7 @@
 import android.content.res.TypedArray;
 import android.os.UserHandle;
 import android.util.AttributeSet;
+import android.view.Display;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -203,4 +204,16 @@
             mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
         }
     }
+
+    /**
+     * @return The id of the display the button is on or Display.INVALID_DISPLAY if it's not yet on
+     *         a display.
+     */
+    public int getDisplayId() {
+        Display display = getDisplay();
+        if (display == null) {
+            return Display.INVALID_DISPLAY;
+        }
+        return display.getDisplayId();
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
index 7811a1c..d20038d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
@@ -22,10 +22,13 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.view.Display;
+import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup;
 
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -40,15 +43,16 @@
 @Singleton
 public class CarFacetButtonController {
 
-    protected HashMap<String, CarFacetButton> mButtonsByCategory = new HashMap<>();
-    protected HashMap<String, CarFacetButton> mButtonsByPackage = new HashMap<>();
-    protected HashMap<String, CarFacetButton> mButtonsByComponentName = new HashMap<>();
-    protected CarFacetButton mSelectedFacetButton;
+    protected ButtonMap mButtonsByCategory = new ButtonMap();
+    protected ButtonMap mButtonsByPackage = new ButtonMap();
+    protected ButtonMap mButtonsByComponentName = new ButtonMap();
+    protected HashSet<CarFacetButton> mSelectedFacetButtons;
     protected Context mContext;
 
     @Inject
     public CarFacetButtonController(Context context) {
         mContext = context;
+        mSelectedFacetButtons = new HashSet<>();
     }
 
     /**
@@ -59,27 +63,40 @@
     public void addFacetButton(CarFacetButton facetButton) {
         String[] categories = facetButton.getCategories();
         for (int i = 0; i < categories.length; i++) {
-            mButtonsByCategory.put(categories[i], facetButton);
+            mButtonsByCategory.add(categories[i], facetButton);
         }
 
         String[] facetPackages = facetButton.getFacetPackages();
         for (int i = 0; i < facetPackages.length; i++) {
-            mButtonsByPackage.put(facetPackages[i], facetButton);
+            mButtonsByPackage.add(facetPackages[i], facetButton);
         }
         String[] componentNames = facetButton.getComponentName();
         for (int i = 0; i < componentNames.length; i++) {
-            mButtonsByComponentName.put(componentNames[i], facetButton);
+            mButtonsByComponentName.add(componentNames[i], facetButton);
         }
-        // Using the following as a default button for display id info it's not
-        // attached to a screen at this point so it can't be extracted here.
-        mSelectedFacetButton = facetButton;
     }
 
     public void removeAll() {
         mButtonsByCategory.clear();
         mButtonsByPackage.clear();
         mButtonsByComponentName.clear();
-        mSelectedFacetButton = null;
+        mSelectedFacetButtons.clear();
+    }
+
+    /**
+     * Iterate through a view looking for CarFacetButtons and adding them to the controller if found
+     *
+     * @param v the View that may contain CarFacetButtons
+     */
+    public void addAllFacetButtons(View v) {
+        if (v instanceof CarFacetButton) {
+            addFacetButton((CarFacetButton) v);
+        } else if (v instanceof ViewGroup) {
+            ViewGroup viewGroup = (ViewGroup) v;
+            for (int i = 0; i < viewGroup.getChildCount(); i++) {
+                addAllFacetButtons(viewGroup.getChildAt(i));
+            }
+        }
     }
 
     /**
@@ -94,12 +111,10 @@
      * @param stackInfoList of the currently running application
      */
     public void taskChanged(List<ActivityManager.StackInfo> stackInfoList) {
-        int displayId = getDisplayId();
         ActivityManager.StackInfo validStackInfo = null;
-        for (ActivityManager.StackInfo stackInfo : stackInfoList) {
-            // If the display id is unknown or it matches the stack, it's valid for use
-            if ((displayId == -1 || displayId == stackInfo.displayId)
-                    && stackInfo.topActivity != null) {
+        for (ActivityManager.StackInfo stackInfo :stackInfoList) {
+            // Find the first stack info with a topActivity
+            if (stackInfo.topActivity != null) {
                 validStackInfo = stackInfo;
                 break;
             }
@@ -110,12 +125,20 @@
             return;
         }
 
-        if (mSelectedFacetButton != null) {
-            mSelectedFacetButton.setSelected(false);
+        if (mSelectedFacetButtons != null) {
+            Iterator<CarFacetButton> iterator = mSelectedFacetButtons.iterator();
+            while(iterator.hasNext()) {
+                CarFacetButton carFacetButton = iterator.next();
+                if (carFacetButton.getDisplayId() == validStackInfo.displayId) {
+                    carFacetButton.setSelected(false);
+                    iterator.remove();
+                }
+            }
         }
 
         String packageName = validStackInfo.topActivity.getPackageName();
-        CarFacetButton facetButton = findFacetButtongByComponentName(validStackInfo.topActivity);
+        HashSet<CarFacetButton> facetButton =
+                findFacetButtonByComponentName(validStackInfo.topActivity);
         if (facetButton == null) {
             facetButton = mButtonsByPackage.get(packageName);
         }
@@ -127,26 +150,21 @@
             }
         }
 
-        if (facetButton != null && facetButton.getVisibility() == View.VISIBLE) {
-            facetButton.setSelected(true);
-            mSelectedFacetButton = facetButton;
-        }
-
-    }
-
-    private int getDisplayId() {
-        if (mSelectedFacetButton != null) {
-            Display display = mSelectedFacetButton.getDisplay();
-            if (display != null) {
-                return display.getDisplayId();
+        if (facetButton != null) {
+            for (CarFacetButton carFacetButton : facetButton) {
+                if (carFacetButton.getDisplayId() == validStackInfo.displayId) {
+                    carFacetButton.setSelected(true);
+                    mSelectedFacetButtons.add(carFacetButton);
+                }
             }
         }
-        return -1;
+
     }
 
-    private CarFacetButton findFacetButtongByComponentName(ComponentName componentName) {
-        CarFacetButton button = mButtonsByComponentName.get(componentName.flattenToShortString());
-        return (button != null) ? button :
+    private HashSet<CarFacetButton> findFacetButtonByComponentName(ComponentName componentName) {
+        HashSet<CarFacetButton> buttons =
+                mButtonsByComponentName.get(componentName.flattenToShortString());
+        return (buttons != null) ? buttons :
                 mButtonsByComponentName.get(componentName.flattenToString());
     }
 
@@ -168,4 +186,18 @@
         }
         return null;
     }
+
+    // simple multi-map
+    private static class ButtonMap extends HashMap<String, HashSet<CarFacetButton>> {
+
+        public boolean add(String key, CarFacetButton value) {
+            if (containsKey(key)) {
+                return get(key).add(value);
+            }
+            HashSet<CarFacetButton> set = new HashSet<>();
+            set.add(value);
+            put(key, set);
+            return true;
+        }
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 9bcc1ab..44e8874 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -187,11 +187,13 @@
         if (mIsKeyguard) {
             updateNavBarForKeyguardContent();
         }
+        // CarFacetButtonController was reset therefore we need to re-add the status bar elements
+        // to the controller.
+        mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow);
     }
 
     private void addTemperatureViewToController(View v) {
         if (v instanceof TemperatureView) {
-            Log.d(TAG, "addTemperatureViewToController: found ");
             mHvacController.addHvacTextView((TemperatureView) v);
         } else if (v instanceof ViewGroup) {
             ViewGroup viewGroup = (ViewGroup) v;
diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml
index a72e4e2..2a66db1 100644
--- a/packages/DynamicSystemInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -13,11 +13,11 @@
     <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string>
 
     <!-- Displayed on notification: AndroidOnTap installation is completed [CHAR LIMIT=128] -->
-    <string name="notification_install_completed">New system is ready, you can reboot into it or discard it.</string>
+    <string name="notification_install_completed">System update is ready. To finish installing, restart your device.</string>
     <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] -->
-    <string name="notification_install_inprogress">Installation is in progress.</string>
+    <string name="notification_install_inprogress">Install in progress</string>
     <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] -->
-    <string name="notification_install_failed">Installation Failed.</string>
+    <string name="notification_install_failed">Install Failed</string>
     <!-- Displayed on notification: We are running in AndroidOnTap [CHAR LIMIT=128] -->
     <string name="notification_dynsystem_in_use">We are running in AndroidOnTap.</string>
 
@@ -27,12 +27,12 @@
     <string name="notification_action_discard">Discard</string>
     <!-- Action on notification: Uninstall AndroidOnTap [CHAR LIMIT=16] -->
     <string name="notification_action_uninstall">Uninstall</string>
-    <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
-    <string name="notification_action_reboot_to_dynsystem">Reboot</string>
+    <!-- Action on notification: Restart to AndroidOnTap [CHAR LIMIT=16] -->
+    <string name="notification_action_reboot_to_dynsystem">Restart</string>
 
     <!-- Toast when installed AndroidOnTap is discarded [CHAR LIMIT=64] -->
     <string name="toast_dynsystem_discarded">Installed AndroidOnTap is discarded.</string>
     <!-- Toast when we fail to launch into AndroidOnTap [CHAR LIMIT=64] -->
-    <string name="toast_failed_to_reboot_to_dynsystem">Failed to reboot into AndroidOnTap.</string>
+    <string name="toast_failed_to_reboot_to_dynsystem">Failed to restart to AndroidOnTap.</string>
 
 </resources>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
index 5c6885a..43d7d8f 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
@@ -326,6 +326,8 @@
         } else if (status == STATUS_READY) {
             startForeground(NOTIFICATION_ID,
                     buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
+        } else {
+            stopSelf();
         }
     }
 
@@ -380,13 +382,13 @@
                 builder.setContentText(getString(R.string.notification_install_completed));
 
                 builder.addAction(new Notification.Action.Builder(
-                        null, getString(R.string.notification_action_reboot_to_dynsystem),
-                        createPendingIntent(ACTION_REBOOT_TO_DYN_SYSTEM)).build());
-
-                builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_discard),
                         createPendingIntent(ACTION_DISCARD_INSTALL)).build());
 
+                builder.addAction(new Notification.Action.Builder(
+                        null, getString(R.string.notification_action_reboot_to_dynsystem),
+                        createPendingIntent(ACTION_REBOOT_TO_DYN_SYSTEM)).build());
+
                 break;
 
             case STATUS_IN_USE:
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 45a59a3..73bfd30 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -17,7 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     package="android.ext.services"
-    android:versionCode="200000000"
+    android:versionCode="210000000"
     android:versionName="1"
     coreApp="true">
 
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 262e6f6..5817118 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -39,6 +39,7 @@
         ":services-networkstack-shared-srcs",
     ],
     static_libs: [
+        "androidx.annotation_annotation",
         "ipmemorystore-client",
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index b4588e0..ac05c44 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -19,7 +19,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.android.networkstack"
   android:sharedUserId="android.uid.networkstack"
-  android:versionCode="200000000"
+  android:versionCode="210000000"
   android:versionName="29 system image"
 >
 
diff --git a/packages/NetworkStack/res/values/config.xml b/packages/NetworkStack/res/values/config.xml
index 52425e5..90f96e0 100644
--- a/packages/NetworkStack/res/values/config.xml
+++ b/packages/NetworkStack/res/values/config.xml
@@ -1,5 +1,38 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <!-- Captive portal http url -->
-    <string name="config_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
+    <!--
+    OEMs that wish to change the below settings must do so via a runtime resource overlay package
+    and *NOT* by changing this file. This file is part of the NetworkStack mainline module.
+    The overlays must apply to the config_* values, not the default_* values. The default_*
+    values are meant to be the default when no other configuration is specified.
+    -->
+
+    <!-- HTTP URL for network validation, to use for detecting captive portals. -->
+    <string name="default_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
+
+    <!-- HTTPS URL for network validation, to use for confirming internet connectivity. -->
+    <string name="default_captive_portal_https_url" translatable="false">https://www.google.com/generate_204</string>
+
+    <!-- List of fallback URLs to use for detecting captive portals. -->
+    <string-array name="default_captive_portal_fallback_urls" translatable="false">
+        <item>http://www.google.com/gen_204</item>
+        <item>http://play.googleapis.com/generate_204</item>
+    </string-array>
+
+    <!-- List of fallback probe specs to use for detecting captive portals.
+         This is an alternative to fallback URLs that provides more flexibility on detection rules.
+         Empty, so unused by default. -->
+    <string-array name="default_captive_portal_fallback_probe_specs" translatable="false">
+    </string-array>
+
+    <!-- Configuration hooks for the above settings.
+         Empty by default but may be overridden by RROs. -->
+    <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
+    <string name="config_captive_portal_http_url" translatable="false"></string>
+    <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
+    <string name="config_captive_portal_https_url" translatable="false"></string>
+    <string-array name="config_captive_portal_fallback_urls" translatable="false">
+    </string-array>
+    <string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
+    </string-array>
 </resources>
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index c1f178a..80d139c 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -51,6 +51,7 @@
 import android.text.TextUtils;
 import android.util.LocalLog;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -298,6 +299,7 @@
     private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
     private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
     private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
+    private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15;
 
     // Internal commands to use instead of trying to call transitionTo() inside
     // a given State's enter() method. Calling transitionTo() from enter/exit
@@ -364,6 +366,8 @@
     private String mTcpBufferSizes;
     private ProxyInfo mHttpProxy;
     private ApfFilter mApfFilter;
+    private String mL2Key; // The L2 key for this network, for writing into the memory store
+    private String mGroupHint; // The group hint for this network, for writing into the memory store
     private boolean mMulticastFiltering;
     private long mStartTimeMillis;
 
@@ -524,6 +528,11 @@
             IpClient.this.stop();
         }
         @Override
+        public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.setL2KeyAndGroupHint(l2Key, groupHint);
+        }
+        @Override
         public void setTcpBufferSizes(String tcpBufferSizes) {
             checkNetworkStackCallingPermission();
             IpClient.this.setTcpBufferSizes(tcpBufferSizes);
@@ -652,6 +661,13 @@
     }
 
     /**
+     * Set the L2 key and group hint for storing info into the memory store.
+     */
+    public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+        sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint));
+    }
+
+    /**
      * Set the HTTP Proxy configuration to use.
      *
      * This may be called, repeatedly, at any time before or after a call to
@@ -1068,6 +1084,10 @@
             return true;
         }
         final int delta = setLinkProperties(newLp);
+        // Most of the attributes stored in the memory store are deduced from
+        // the link properties, therefore when the properties update the memory
+        // store record should be updated too.
+        maybeSaveNetworkToIpMemoryStore();
         if (sendCallbacks) {
             dispatchCallback(delta, newLp);
         }
@@ -1083,6 +1103,7 @@
             Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
         }
         mCallback.onNewDhcpResults(dhcpResults);
+        maybeSaveNetworkToIpMemoryStore();
         dispatchCallback(delta, newLp);
     }
 
@@ -1213,6 +1234,10 @@
         mInterfaceCtrl.clearAllAddresses();
     }
 
+    private void maybeSaveNetworkToIpMemoryStore() {
+        // TODO : implement this
+    }
+
     class StoppedState extends State {
         @Override
         public void enter() {
@@ -1258,6 +1283,13 @@
                     handleLinkPropertiesUpdate(NO_CALLBACKS);
                     break;
 
+                case CMD_UPDATE_L2KEY_GROUPHINT: {
+                    final Pair<String, String> args = (Pair<String, String>) msg.obj;
+                    mL2Key = args.first;
+                    mGroupHint = args.second;
+                    break;
+                }
+
                 case CMD_SET_MULTICAST_FILTER:
                     mMulticastFiltering = (boolean) msg.obj;
                     break;
@@ -1357,6 +1389,20 @@
                     }
                     break;
 
+                case CMD_UPDATE_L2KEY_GROUPHINT: {
+                    final Pair<String, String> args = (Pair<String, String>) msg.obj;
+                    mL2Key = args.first;
+                    mGroupHint = args.second;
+                    // TODO : attributes should be saved to the memory store with
+                    // these new values if they differ from the previous ones.
+                    // If the state machine is in pure StartedState, then the values to input
+                    // are not known yet and should be updated when the LinkProperties are updated.
+                    // If the state machine is in RunningState (which is a child of StartedState)
+                    // then the next NUD check should be used to store the new values to avoid
+                    // inputting current values for what may be a different L3 network.
+                    break;
+                }
+
                 case EVENT_PROVISIONING_TIMEOUT:
                     handleProvisioningFailure();
                     break;
diff --git a/packages/NetworkStack/src/android/net/util/DataStallUtils.java b/packages/NetworkStack/src/android/net/util/DataStallUtils.java
new file mode 100644
index 0000000..b6dbeb1
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/DataStallUtils.java
@@ -0,0 +1,72 @@
+/*
+ * 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.net.util;
+
+/**
+ * Collection of utilities for data stall.
+ */
+public class DataStallUtils {
+    /**
+     * Detect data stall via using dns timeout counts.
+     */
+    public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
+    // Default configuration values for data stall detection.
+    public static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
+    public static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
+    public static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
+    /**
+     * The threshold value for the number of consecutive dns timeout events received to be a
+     * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this
+     * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note
+     * that the value should be {@code > 0} if the DNS data stall detection is enabled.
+     *
+     */
+    public static final String CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
+            "data_stall_consecutive_dns_timeout_threshold";
+
+    /**
+     * The minimal time interval in milliseconds for data stall reevaluation.
+     *
+     */
+    public static final String CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL =
+            "data_stall_min_evaluate_interval";
+
+    /**
+     * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting
+     * a data stall.
+     *
+     */
+    public static final String CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD =
+            "data_stall_valid_dns_time_threshold";
+
+    /**
+     * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing
+     * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values.
+     *
+     * Type: int
+     * Valid values:
+     *   {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal.
+     */
+    public static final String CONFIG_DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
+    public static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = DATA_STALL_EVALUATION_TYPE_DNS;
+    // The default number of DNS events kept of the log kept for dns signal evaluation. Each event
+    // is represented by a {@link com.android.server.connectivity.NetworkMonitor#DnsResult} objects.
+    // It's also the size of array of {@link com.android.server.connectivity.nano.DnsEvent} kept in
+    // metrics. Note that increasing the size may cause statsd log buffer bust. Need to check the
+    // design in statsd when you try to increase the size.
+    public static final int DEFAULT_DNS_LOG_SIZE = 20;
+}
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index dada61c..e7a607b 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -32,6 +32,9 @@
  * Collection of utilities for the network stack.
  */
 public class NetworkStackUtils {
+    // TODO: Refer to DeviceConfig definition.
+    public static final String NAMESPACE_CONNECTIVITY = "connectivity";
+
     static {
         System.loadLibrary("networkstackutilsjni");
     }
@@ -104,6 +107,24 @@
     }
 
     /**
+     * Look up the value of a property for a particular namespace from {@link DeviceConfig}.
+     * @param namespace The namespace containing the property to look up.
+     * @param name The name of the property to look up.
+     * @param defaultValue The value to return if the property does not exist or has no non-null
+     *                     value.
+     * @return the corresponding value, or defaultValue if none exists.
+     */
+    public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
+            int defaultValue) {
+        String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */);
+        try {
+            return (value != null) ? Integer.parseInt(value) : defaultValue;
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
+    /**
      * Attaches a socket filter that accepts DHCP packets to the given socket.
      */
     public static native void attachDhcpFilter(FileDescriptor fd) throws SocketException;
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 8f7d988..588dcf2 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -28,12 +28,23 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.captiveportal.CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs;
 import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
 import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
 import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
 import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
+import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.DataStallUtils.DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_EVALUATION_TYPES;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS;
+import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE;
+import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY;
 import static android.net.util.NetworkStackUtils.isEmpty;
-import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -42,6 +53,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -60,6 +72,7 @@
 import android.net.metrics.ValidationProbeEvent;
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
+import android.net.util.NetworkStackUtils;
 import android.net.util.SharedLog;
 import android.net.util.Stopwatch;
 import android.net.wifi.WifiInfo;
@@ -80,6 +93,9 @@
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.annotation.ArrayRes;
+import androidx.annotation.StringRes;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.RingBufferIndices;
 import com.android.internal.util.State;
@@ -94,7 +110,6 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -102,6 +117,7 @@
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
 
 /**
  * {@hide}
@@ -111,33 +127,12 @@
     private static final boolean DBG  = true;
     private static final boolean VDBG = false;
     private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
-    // TODO: use another permission for CaptivePortalLoginActivity once it has its own certificate
-    private static final String PERMISSION_NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
-    // 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_FALLBACK_URL  = "http://www.google.com/gen_204";
-    private static final String DEFAULT_OTHER_FALLBACK_URLS =
-            "http://play.googleapis.com/generate_204";
     private static final String DEFAULT_USER_AGENT    = "Mozilla/5.0 (X11; Linux x86_64) "
                                                       + "AppleWebKit/537.36 (KHTML, like Gecko) "
                                                       + "Chrome/60.0.3112.32 Safari/537.36";
 
     private static final int SOCKET_TIMEOUT_MS = 10000;
     private static final int PROBE_TIMEOUT_MS  = 3000;
-
-    // Default configuration values for data stall detection.
-    private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
-    private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
-    private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
-
-    private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES =
-            DATA_STALL_EVALUATION_TYPE_DNS;
-    // Reevaluate it as intending to increase the number. Larger log size may cause statsd
-    // log buffer bust and have stats log lost.
-    private static final int DEFAULT_DNS_LOG_SIZE = 20;
-
     enum EvaluationResult {
         VALIDATED(true),
         CAPTIVE_PORTAL(false);
@@ -379,7 +374,7 @@
         mUseHttps = getUseHttpsValidation();
         mCaptivePortalUserAgent = getCaptivePortalUserAgent();
         mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
-        mCaptivePortalHttpUrl = makeURL(deps.getCaptivePortalServerHttpUrl(context));
+        mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl());
         mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
         mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
         mRandom = deps.getRandom();
@@ -388,7 +383,7 @@
         mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold);
         mDataStallMinEvaluateTime = getDataStallMinEvaluateTime();
         mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
-        mDataStallEvaluationType = getDataStallEvalutionType();
+        mDataStallEvaluationType = getDataStallEvaluationType();
 
         // Provide empty LinkProperties and NetworkCapabilities to make sure they are never null,
         // even before notifyNetworkConnected.
@@ -542,10 +537,6 @@
                     return HANDLED;
                 case CMD_NETWORK_DISCONNECTED:
                     logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED);
-                    if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
-                        mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
-                        mLaunchCaptivePortalAppBroadcastReceiver = null;
-                    }
                     quit();
                     return HANDLED;
                 case CMD_FORCE_REEVALUATION:
@@ -779,7 +770,10 @@
 
         @Override
         public void exit() {
-            mLaunchCaptivePortalAppBroadcastReceiver = null;
+            if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
+                mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
+                mLaunchCaptivePortalAppBroadcastReceiver = null;
+            }
             hideProvisioningNotification();
         }
     }
@@ -1180,53 +1174,67 @@
     }
 
     private String getCaptivePortalServerHttpsUrl() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
+        return getSettingFromResource(mContext, R.string.config_captive_portal_https_url,
+                R.string.default_captive_portal_https_url,
+                Settings.Global.CAPTIVE_PORTAL_HTTPS_URL);
+    }
+
+    /**
+     * Get the captive portal server HTTP URL that is configured on the device.
+     *
+     * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as
+     * it has its own updatable strategies to detect captive portals. The framework only advises
+     * on one URL that can be used, while NetworkMonitor may implement more complex logic.
+     */
+    public String getCaptivePortalServerHttpUrl() {
+        return getSettingFromResource(mContext, R.string.config_captive_portal_http_url,
+                R.string.default_captive_portal_http_url,
+                Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
     }
 
     private int getConsecutiveDnsTimeoutThreshold() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
                 DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD);
     }
 
     private int getDataStallMinEvaluateTime() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL,
                 DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS);
     }
 
     private int getDataStallValidDnsTimeThreshold() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD,
                 DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS);
     }
 
-    private int getDataStallEvalutionType() {
-        return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE,
+    private int getDataStallEvaluationType() {
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_EVALUATION_TYPE,
                 DEFAULT_DATA_STALL_EVALUATION_TYPES);
     }
 
     private URL[] makeCaptivePortalFallbackUrls() {
         try {
-            String separator = ",";
-            String firstUrl = mDependencies.getSetting(mContext,
-                    Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
-            String joinedUrls = firstUrl + separator + mDependencies.getSetting(mContext,
-                    Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
-                    DEFAULT_OTHER_FALLBACK_URLS);
-            List<URL> urls = new ArrayList<>();
-            for (String s : joinedUrls.split(separator)) {
-                URL u = makeURL(s);
-                if (u == null) {
-                    continue;
-                }
-                urls.add(u);
+            final String firstUrl = mDependencies.getSetting(mContext,
+                    Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, null);
+
+            final URL[] settingProviderUrls;
+            if (!TextUtils.isEmpty(firstUrl)) {
+                final String otherUrls = mDependencies.getSetting(mContext,
+                        Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
+                // otherUrls may be empty, but .split() ignores trailing empty strings
+                final String separator = ",";
+                final String[] urls = (firstUrl + separator + otherUrls).split(separator);
+                settingProviderUrls = convertStrings(urls, this::makeURL, new URL[0]);
+            } else {
+                settingProviderUrls = new URL[0];
             }
-            if (urls.isEmpty()) {
-                Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
-            }
-            return urls.toArray(new URL[urls.size()]);
+
+            return getArrayConfig(settingProviderUrls, R.array.config_captive_portal_fallback_urls,
+                    R.array.default_captive_portal_fallback_urls, this::makeURL);
         } catch (Exception e) {
             // Don't let a misconfiguration bootloop the system.
             Log.e(TAG, "Error parsing configured fallback URLs", e);
@@ -1238,15 +1246,14 @@
         try {
             final String settingsValue = mDependencies.getSetting(
                     mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
-            // Probe specs only used if configured in settings
-            if (TextUtils.isEmpty(settingsValue)) {
-                return null;
-            }
+            final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0];
+            final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue)
+                    ? emptySpecs
+                    : parseCaptivePortalProbeSpecs(settingsValue).toArray(emptySpecs);
 
-            final Collection<CaptivePortalProbeSpec> specs =
-                    CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
-            final CaptivePortalProbeSpec[] specsArray = new CaptivePortalProbeSpec[specs.size()];
-            return specs.toArray(specsArray);
+            return getArrayConfig(providerValue, R.array.config_captive_portal_fallback_probe_specs,
+                    R.array.default_captive_portal_fallback_probe_specs,
+                    CaptivePortalProbeSpec::parseSpecOrNull);
         } catch (Exception e) {
             // Don't let a misconfiguration bootloop the system.
             Log.e(TAG, "Error parsing configured fallback probe specs", e);
@@ -1254,6 +1261,83 @@
         }
     }
 
+    /**
+     * Read a setting from a resource or the settings provider.
+     *
+     * <p>The configuration resource is prioritized, then the provider value, then the default
+     * resource value.
+     * @param context The context
+     * @param configResource The resource id for the configuration parameter
+     * @param defaultResource The resource id for the default value
+     * @param symbol The symbol in the settings provider
+     * @return The best available value
+     */
+    @NonNull
+    private String getSettingFromResource(@NonNull final Context context,
+            @StringRes int configResource, @StringRes int defaultResource,
+            @NonNull String symbol) {
+        final Resources res = context.getResources();
+        String setting = res.getString(configResource);
+
+        if (!TextUtils.isEmpty(setting)) return setting;
+
+        setting = mDependencies.getSetting(context, symbol, null);
+        if (!TextUtils.isEmpty(setting)) return setting;
+
+        return res.getString(defaultResource);
+    }
+
+    /**
+     * Get an array configuration from resources or the settings provider.
+     *
+     * <p>The configuration resource is prioritized, then the provider values, then the default
+     * resource values.
+     * @param providerValue Values obtained from the setting provider.
+     * @param configResId ID of the configuration resource.
+     * @param defaultResId ID of the default resource.
+     * @param resourceConverter Converter from the resource strings to stored setting class. Null
+     *                          return values are ignored.
+     */
+    private <T> T[] getArrayConfig(@NonNull T[] providerValue, @ArrayRes int configResId,
+            @ArrayRes int defaultResId, @NonNull Function<String, T> resourceConverter) {
+        final Resources res = mContext.getResources();
+        String[] configValue = res.getStringArray(configResId);
+
+        if (configValue.length == 0) {
+            if (providerValue.length > 0) {
+                return providerValue;
+            }
+
+            configValue = res.getStringArray(defaultResId);
+        }
+
+        return convertStrings(configValue, resourceConverter, Arrays.copyOf(providerValue, 0));
+    }
+
+    /**
+     * Convert a String array to an array of some other type using the specified converter.
+     *
+     * <p>Any null value, or value for which the converter throws a {@link RuntimeException}, will
+     * not be added to the output array, so the output array may be smaller than the input.
+     */
+    private <T> T[] convertStrings(
+            @NonNull String[] strings, Function<String, T> converter, T[] emptyArray) {
+        final ArrayList<T> convertedValues = new ArrayList<>(strings.length);
+        for (String configString : strings) {
+            T convertedValue = null;
+            try {
+                convertedValue = converter.apply(configString);
+            } catch (Exception e) {
+                Log.e(TAG, "Error parsing configuration", e);
+                // Fall through
+            }
+            if (convertedValue != null) {
+                convertedValues.add(convertedValue);
+            }
+        }
+        return convertedValues.toArray(emptyArray);
+    }
+
     private String getCaptivePortalUserAgent() {
         return mDependencies.getSetting(mContext,
                 Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
@@ -1695,19 +1779,6 @@
         }
 
         /**
-         * Get the captive portal server HTTP URL that is configured on the device.
-         *
-         * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as
-         * it has its own updatable strategies to detect captive portals. The framework only advises
-         * on one URL that can be used, while  NetworkMonitor may implement more complex logic.
-         */
-        public String getCaptivePortalServerHttpUrl(Context context) {
-            final String defaultUrl =
-                    context.getResources().getString(R.string.config_captive_portal_http_url);
-            return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(context, defaultUrl);
-        }
-
-        /**
          * 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.
@@ -1726,6 +1797,33 @@
             return value != null ? value : defaultValue;
         }
 
+        /**
+         * Look up the value of a property in DeviceConfig.
+         * @param namespace The namespace containing the property to look up.
+         * @param name The name of the property to look up.
+         * @param defaultValue The value to return if the property does not exist or has no non-null
+         *                     value.
+         * @return the corresponding value, or defaultValue if none exists.
+         */
+        @Nullable
+        public String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
+                @Nullable String defaultValue) {
+            return NetworkStackUtils.getDeviceConfigProperty(namespace, name, defaultValue);
+        }
+
+        /**
+         * Look up the value of a property in DeviceConfig.
+         * @param namespace The namespace containing the property to look up.
+         * @param name The name of the property to look up.
+         * @param defaultValue The value to return if the property does not exist or has no non-null
+         *                     value.
+         * @return the corresponding value, or defaultValue if none exists.
+         */
+        public int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
+                int defaultValue) {
+            return NetworkStackUtils.getDeviceConfigPropertyInt(namespace, name, defaultValue);
+        }
+
         public static final Dependencies DEFAULT = new Dependencies();
     }
 
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index eee12d6..5f80006 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -28,6 +28,7 @@
 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.AlarmManager;
@@ -40,7 +41,9 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.MacAddress;
+import android.net.NetworkStackIpMemoryStore;
 import android.net.RouteInfo;
+import android.net.ipmemorystore.NetworkAttributes;
 import android.net.shared.InitialConfiguration;
 import android.net.shared.ProvisioningConfiguration;
 import android.net.util.InterfaceParams;
@@ -81,6 +84,8 @@
     // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
     private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
     private static final int TEST_TIMEOUT_MS = 400;
+    private static final String TEST_L2KEY = "some l2key";
+    private static final String TEST_GROUPHINT = "some grouphint";
 
     @Mock private Context mContext;
     @Mock private ConnectivityManager mCm;
@@ -92,6 +97,7 @@
     @Mock private IpClient.Dependencies mDependencies;
     @Mock private ContentResolver mContentResolver;
     @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
+    @Mock private NetworkStackIpMemoryStore mIpMemoryStore;
 
     private NetworkObserver mObserver;
     private InterfaceParams mIfParams;
@@ -141,6 +147,12 @@
         return empty;
     }
 
+    private void verifyNetworkAttributesStored(final String l2Key,
+            final NetworkAttributes attributes) {
+        // TODO : when storing is implemented, turn this on
+        // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any());
+    }
+
     @Test
     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
         setTestInterfaceParams(null);
@@ -173,6 +185,7 @@
         setTestInterfaceParams(TEST_IFNAME);
         final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
                 mNetworkStackServiceManager, mDependencies);
+        verifyNoMoreInteractions(mIpMemoryStore);
         ipc.shutdown();
     }
 
@@ -183,6 +196,7 @@
                 mNetworkStackServiceManager, mDependencies);
         ipc.startProvisioning(new ProvisioningConfiguration());
         verify(mCb, times(1)).onProvisioningFailure(any());
+        verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
         ipc.shutdown();
     }
 
@@ -202,6 +216,7 @@
         verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
         verify(mCb, never()).onProvisioningFailure(any());
+        verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
 
         ipc.shutdown();
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
@@ -214,6 +229,8 @@
     public void testProvisioningWithInitialConfiguration() throws Exception {
         final String iface = TEST_IFNAME;
         final IpClient ipc = makeIpClient(iface);
+        final String l2Key = TEST_L2KEY;
+        final String groupHint = TEST_GROUPHINT;
 
         String[] addresses = {
             "fe80::a4be:f92:e1f7:22d1/64",
@@ -232,6 +249,7 @@
         verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
         verify(mCb, never()).onProvisioningFailure(any());
+        ipc.setL2KeyAndGroupHint(l2Key, groupHint);
 
         for (String addr : addresses) {
             String[] parts = addr.split("/");
@@ -253,12 +271,16 @@
         LinkProperties want = linkproperties(links(addresses), routes(prefixes));
         want.setInterfaceName(iface);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
+        verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder()
+                .setGroupHint(groupHint)
+                .build());
 
         ipc.shutdown();
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
                 .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
+        verifyNoMoreInteractions(mIpMemoryStore);
     }
 
     @Test
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index 6665aae..fa41284 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -21,7 +21,11 @@
 import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
 import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
+import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -30,7 +34,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
@@ -44,7 +47,10 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.INetworkMonitorCallbacks;
 import android.net.InetAddresses;
@@ -72,6 +78,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -85,6 +92,7 @@
 import java.net.HttpURLConnection;
 import java.net.InetAddress;
 import java.net.URL;
+import java.util.HashSet;
 import java.util.Random;
 
 import javax.net.ssl.SSLHandshakeException;
@@ -95,6 +103,7 @@
     private static final String LOCATION_HEADER = "location";
 
     private @Mock Context mContext;
+    private @Mock Resources mResources;
     private @Mock IpConnectivityLog mLogger;
     private @Mock SharedLog mValidationLogger;
     private @Mock NetworkInfo mNetworkInfo;
@@ -113,8 +122,10 @@
     private @Mock WifiInfo mWifiInfo;
     private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
 
-    private static final int TEST_NETID = 4242;
+    private HashSet<WrappedNetworkMonitor> mCreatedNetworkMonitors;
+    private HashSet<BroadcastReceiver> mRegisteredReceivers;
 
+    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";
     private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
@@ -150,14 +161,20 @@
                 .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
         when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
                 anyInt())).thenReturn(1);
-        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(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
+                .thenReturn(TEST_HTTP_URL);
+        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), any()))
+                .thenReturn(TEST_HTTPS_URL);
+
         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);
+        when(mContext.getResources()).thenReturn(mResources);
+
+        when(mResources.getString(anyInt())).thenReturn("");
+        when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
 
         when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
         setFallbackUrl(TEST_FALLBACK_URL);
@@ -187,14 +204,45 @@
                 InetAddresses.parseNumericAddress("192.168.0.0")
         }).when(mNetwork).getAllByName(any());
 
+        when(mContext.registerReceiver(any(BroadcastReceiver.class), any())).then((invocation) -> {
+            mRegisteredReceivers.add(invocation.getArgument(0));
+            return new Intent();
+        });
+
+        doAnswer((invocation) -> {
+            mRegisteredReceivers.remove(invocation.getArgument(0));
+            return null;
+        }).when(mContext).unregisterReceiver(any());
+
         setMinDataStallEvaluateInterval(500);
         setDataStallEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
         setValidDataStallDnsTimeThreshold(500);
         setConsecutiveDnsTimeoutThreshold(5);
+
+        mCreatedNetworkMonitors = new HashSet<>();
+        mRegisteredReceivers = new HashSet<>();
+    }
+
+    @After
+    public void tearDown() {
+        assertTrue(mCreatedNetworkMonitors.size() > 0);
+        // Make a local copy of mCreatedNetworkMonitors because during the iteration below,
+        // WrappedNetworkMonitor#onQuitting will delete elements from it on the handler threads.
+        WrappedNetworkMonitor[] networkMonitors = mCreatedNetworkMonitors.toArray(
+                new WrappedNetworkMonitor[0]);
+        for (WrappedNetworkMonitor nm : networkMonitors) {
+            nm.notifyNetworkDisconnected();
+            nm.awaitQuit();
+        }
+        assertEquals("NetworkMonitor still running after disconnect",
+                0, mCreatedNetworkMonitors.size());
+        assertEquals("BroadcastReceiver still registered after disconnect",
+                0, mRegisteredReceivers.size());
     }
 
     private class WrappedNetworkMonitor extends NetworkMonitor {
         private long mProbeTime = 0;
+        private final ConditionVariable mQuitCv = new ConditionVariable(false);
 
         WrappedNetworkMonitor() {
                 super(mContext, mCallbacks, mNetwork, mLogger, mValidationLogger, mDependencies,
@@ -214,12 +262,24 @@
         protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
             generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         }
+
+        @Override
+        protected void onQuitting() {
+            assertTrue(mCreatedNetworkMonitors.remove(this));
+            mQuitCv.open();
+        }
+
+        protected void awaitQuit() {
+            assertTrue("NetworkMonitor did not quit after " + HANDLER_TIMEOUT_MS + "ms",
+                    mQuitCv.block(HANDLER_TIMEOUT_MS));
+        }
     }
 
     private WrappedNetworkMonitor makeMonitor() {
         final WrappedNetworkMonitor nm = new WrappedNetworkMonitor();
         nm.start();
         waitForIdle(nm.getHandler());
+        mCreatedNetworkMonitors.add(nm);
         return nm;
     }
 
@@ -472,6 +532,8 @@
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
                 .showProvisioningNotification(any(), any());
 
+        assertEquals(1, mRegisteredReceivers.size());
+
         // Check that startCaptivePortalApp sends the expected intent.
         nm.launchCaptivePortalApp();
 
@@ -494,6 +556,8 @@
         nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
                 .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+
+        assertEquals(0, mRegisteredReceivers.size());
     }
 
     @Test
@@ -593,24 +657,23 @@
     }
 
     private void setDataStallEvaluationType(int type) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
     }
 
     private void setMinDataStallEvaluateInterval(int time) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
     }
 
     private void setValidDataStallDnsTimeThreshold(int time) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
     }
 
     private void setConsecutiveDnsTimeoutThreshold(int num) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt()))
-            .thenReturn(num);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())).thenReturn(num);
     }
 
     private void setFallbackUrl(String url) {
@@ -635,21 +698,25 @@
 
     private void runPortalNetworkTest() {
         runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+        assertEquals(1, mRegisteredReceivers.size());
         assertNotNull(mNetworkTestedRedirectUrlCaptor.getValue());
     }
 
     private void runNotPortalNetworkTest() {
         runNetworkTest(NETWORK_TEST_RESULT_VALID);
+        assertEquals(0, mRegisteredReceivers.size());
         assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
     }
 
     private void runFailedNetworkTest() {
         runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+        assertEquals(0, mRegisteredReceivers.size());
         assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
     }
 
     private void runPartialConnectivityNetworkTest() {
         runNetworkTest(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY);
+        assertEquals(0, mRegisteredReceivers.size());
         assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
     }
 
@@ -666,6 +733,7 @@
         } catch (RemoteException e) {
             fail("Unexpected exception: " + e);
         }
+        waitForIdle(monitor.getHandler());
 
         return monitor;
     }
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index bde1b25..55ff591 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -43,7 +43,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
@@ -472,16 +471,6 @@
                 mOriginatingUid, mOriginatingPackage);
         switch (appOpMode) {
             case AppOpsManager.MODE_DEFAULT:
-                try {
-                    int result = mIpm.checkUidPermission(
-                            Manifest.permission.REQUEST_INSTALL_PACKAGES, mOriginatingUid);
-                    if (result == PackageManager.PERMISSION_GRANTED) {
-                        initiateInstall();
-                        break;
-                    }
-                } catch (RemoteException exc) {
-                    Log.e(TAG, "Unable to talk to package manager");
-                }
                 mAppOpsManager.setMode(appOpCode, mOriginatingUid,
                         mOriginatingPackage, AppOpsManager.MODE_ERRORED);
                 // fall through
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index c6a995cb..8a39b82 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -34,6 +34,8 @@
     <string name="wifi_security_short_eap" translatable="false">802.1x</string>
     <!-- Do not translate.  Concise terminology for wifi with WPA3 security -->
     <string name="wifi_security_short_sae" translatable="false">WPA3</string>
+    <!-- Do not translate.  Concise terminology for wifi with WPA2/WPA3 transition security -->
+    <string name="wifi_security_short_psk_sae" translatable="false">WPA2/WPA3</string>
     <!-- Do not translate.  Concise terminology for wifi with OWE security -->
     <string name="wifi_security_short_owe" translatable="false">OWE</string>
     <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP Suite-B security -->
@@ -58,6 +60,8 @@
     <string name="wifi_security_passpoint" translatable="false">Passpoint</string>
     <!-- Do not translate.  Terminology for wifi with WPA3 security -->
     <string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
+    <!-- Do not translate.  Terminology for wifi with WPA2/WPA3 Transition mode security -->
+    <string name="wifi_security_psk_sae" translatable="false">WPA2/WPA3-Personal</string>
     <!-- Do not translate.  Terminology for wifi with OWE security -->
     <string name="wifi_security_owe" translatable="false">Enhanced Open</string>
     <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP Suite-B security -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index d4d0519..e02709e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -83,17 +83,18 @@
  * as needed.
  */
 public class ApplicationsState {
-    static final String TAG = "ApplicationsState";
-    static final boolean DEBUG = false;
-    static final boolean DEBUG_LOCKING = false;
+    private static final String TAG = "ApplicationsState";
 
     public static final int SIZE_UNKNOWN = -1;
     public static final int SIZE_INVALID = -2;
 
-    static final Pattern REMOVE_DIACRITICALS_PATTERN
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_LOCKING = false;
+    private static final Object sLock = new Object();
+    private static final Pattern REMOVE_DIACRITICALS_PATTERN
             = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
 
-    static final Object sLock = new Object();
+    @VisibleForTesting
     static ApplicationsState sInstance;
 
     public static ApplicationsState getInstance(Application app) {
@@ -126,13 +127,12 @@
 
     // Information about all applications.  Synchronize on mEntriesMap
     // to protect access to these.
-    final ArrayList<Session> mSessions = new ArrayList<Session>();
-    final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>();
+    final ArrayList<Session> mSessions = new ArrayList<>();
+    final ArrayList<Session> mRebuildingSessions = new ArrayList<>();
     private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
     // Map: userid => (Map: package name => AppEntry)
-    final SparseArray<HashMap<String, AppEntry>> mEntriesMap =
-            new SparseArray<HashMap<String, AppEntry>>();
-    final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>();
+    final SparseArray<HashMap<String, AppEntry>> mEntriesMap = new SparseArray<>();
+    final ArrayList<AppEntry> mAppEntries = new ArrayList<>();
     List<ApplicationInfo> mApplications = new ArrayList<>();
     long mCurId = 1;
     UUID mCurComputingSizeUuid;
@@ -182,9 +182,10 @@
         mInterestingConfigChanges = interestingConfigChanges;
     }
 
-    public static final @SessionFlags int DEFAULT_SESSION_FLAGS =
+    @SessionFlags
+    public static final int DEFAULT_SESSION_FLAGS =
             FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
-            FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER;
+                    FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER;
 
     private ApplicationsState(Application app, IPackageManager iPackageManager) {
         mContext = app;
@@ -194,7 +195,7 @@
         mUm = mContext.getSystemService(UserManager.class);
         mStats = mContext.getSystemService(StorageStatsManager.class);
         for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
-            mEntriesMap.put(userId, new HashMap<String, AppEntry>());
+            mEntriesMap.put(userId, new HashMap<>());
         }
 
         mThread = new HandlerThread("ApplicationsState.Loader",
@@ -683,9 +684,16 @@
     private AppEntry getEntryLocked(ApplicationInfo info) {
         int userId = UserHandle.getUserId(info.uid);
         AppEntry entry = mEntriesMap.get(userId).get(info.packageName);
-        if (DEBUG) Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry);
+        if (DEBUG) {
+            Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry);
+        }
         if (entry == null) {
-            if (DEBUG) Log.i(TAG, "Creating AppEntry for " + info.packageName);
+            if (mHiddenModules.contains(info.packageName)) {
+                return null;
+            }
+            if (DEBUG) {
+                Log.i(TAG, "Creating AppEntry for " + info.packageName);
+            }
             entry = new AppEntry(mContext, info, mCurId++);
             mEntriesMap.get(userId).put(info.packageName, entry);
             mAppEntries.add(entry);
@@ -759,7 +767,8 @@
         boolean mRebuildForeground;
 
         private final boolean mHasLifecycle;
-        @SessionFlags private int mFlags = DEFAULT_SESSION_FLAGS;
+        @SessionFlags
+        private int mFlags = DEFAULT_SESSION_FLAGS;
 
         Session(Callbacks callbacks, Lifecycle lifecycle) {
             mCallbacks = callbacks;
@@ -771,7 +780,8 @@
             }
         }
 
-        public @SessionFlags int getSessionFlags() {
+        @SessionFlags
+        public int getSessionFlags() {
             return mFlags;
         }
 
@@ -863,25 +873,32 @@
                 filter.init(mContext);
             }
 
-            List<AppEntry> apps;
+            final List<AppEntry> apps;
             synchronized (mEntriesMap) {
                 apps = new ArrayList<>(mAppEntries);
             }
 
-            ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
-            if (DEBUG) Log.i(TAG, "Rebuilding...");
-            for (int i = 0; i < apps.size(); i++) {
-                AppEntry entry = apps.get(i);
+            ArrayList<AppEntry> filteredApps = new ArrayList<>();
+            if (DEBUG) {
+                Log.i(TAG, "Rebuilding...");
+            }
+            for (AppEntry entry : apps) {
                 if (entry != null && (filter == null || filter.filterApp(entry))) {
                     synchronized (mEntriesMap) {
-                        if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock");
+                        if (DEBUG_LOCKING) {
+                            Log.v(TAG, "rebuild acquired lock");
+                        }
                         if (comparator != null) {
                             // Only need the label if we are going to be sorting.
                             entry.ensureLabel(mContext);
                         }
-                        if (DEBUG) Log.i(TAG, "Using " + entry.info.packageName + ": " + entry);
+                        if (DEBUG) {
+                            Log.i(TAG, "Using " + entry.info.packageName + ": " + entry);
+                        }
                         filteredApps.add(entry);
-                        if (DEBUG_LOCKING) Log.v(TAG, "rebuild releasing lock");
+                        if (DEBUG_LOCKING) {
+                            Log.v(TAG, "rebuild releasing lock");
+                        }
                     }
                 }
             }
@@ -1290,7 +1307,8 @@
             }
         }
 
-        private @SessionFlags int getCombinedSessionFlags(List<Session> sessions) {
+        @SessionFlags
+        private int getCombinedSessionFlags(List<Session> sessions) {
             synchronized (mEntriesMap) {
                 int flags = 0;
                 for (Session session : sessions) {
@@ -1601,7 +1619,7 @@
             }
             if (object1.info != null && object2.info != null) {
                 compareResult =
-                    sCollator.compare(object1.info.packageName, object2.info.packageName);
+                        sCollator.compare(object1.info.packageName, object2.info.packageName);
                 if (compareResult != 0) {
                     return compareResult;
                 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 46e9129..0d972c5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -28,6 +28,8 @@
     public static final boolean V = false; // verbose logging
     public static final boolean D = true;  // regular logging
 
+    public static final int META_INT_ERROR = -1;
+
     private static ErrorListener sErrorListener;
 
     public static int getConnectionStateSummary(int connectionState) {
@@ -133,20 +135,16 @@
         final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
                 context, cachedDevice);
         final BluetoothDevice bluetoothDevice = cachedDevice.getDevice();
-        final boolean untetheredHeadset = bluetoothDevice != null
-                ? Boolean.parseBoolean(bluetoothDevice.getMetadata(
-                BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
-                : false;
+        final boolean untetheredHeadset = getBooleanMetaData(
+                bluetoothDevice, BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET);
         final int iconSize = context.getResources().getDimensionPixelSize(
                 R.dimen.bt_nearby_icon_size);
         final Resources resources = context.getResources();
 
         // Deal with untethered headset
         if (untetheredHeadset) {
-            final String uriString = bluetoothDevice != null
-                    ? bluetoothDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON)
-                    : null;
-            final Uri iconUri = uriString != null ? Uri.parse(uriString) : null;
+            final Uri iconUri = getUriMetaData(bluetoothDevice,
+                    BluetoothDevice.METADATA_MAIN_ICON);
             if (iconUri != null) {
                 try {
                     context.getContentResolver().takePersistableUriPermission(iconUri,
@@ -194,4 +192,77 @@
 
         return adaptiveIcon;
     }
+
+    /**
+     * Get boolean Bluetooth metadata
+     *
+     * @param bluetoothDevice the BluetoothDevice to get metadata
+     * @param key key value within the list of BluetoothDevice.METADATA_*
+     * @return the boolean metdata
+     */
+    public static boolean getBooleanMetaData(BluetoothDevice bluetoothDevice, int key) {
+        if (bluetoothDevice == null) {
+            return false;
+        }
+        final byte[] data = bluetoothDevice.getMetadata(key);
+        if (data == null) {
+            return false;
+        }
+        return Boolean.parseBoolean(new String(data));
+    }
+
+    /**
+     * Get String Bluetooth metadata
+     *
+     * @param bluetoothDevice the BluetoothDevice to get metadata
+     * @param key key value within the list of BluetoothDevice.METADATA_*
+     * @return the String metdata
+     */
+    public static String getStringMetaData(BluetoothDevice bluetoothDevice, int key) {
+        if (bluetoothDevice == null) {
+            return null;
+        }
+        final byte[] data = bluetoothDevice.getMetadata(key);
+        if (data == null) {
+            return null;
+        }
+        return new String(data);
+    }
+
+    /**
+     * Get integer Bluetooth metadata
+     *
+     * @param bluetoothDevice the BluetoothDevice to get metadata
+     * @param key key value within the list of BluetoothDevice.METADATA_*
+     * @return the int metdata
+     */
+    public static int getIntMetaData(BluetoothDevice bluetoothDevice, int key) {
+        if (bluetoothDevice == null) {
+            return META_INT_ERROR;
+        }
+        final byte[] data = bluetoothDevice.getMetadata(key);
+        if (data == null) {
+            return META_INT_ERROR;
+        }
+        try {
+            return Integer.parseInt(new String(data));
+        } catch (NumberFormatException e) {
+            return META_INT_ERROR;
+        }
+    }
+
+    /**
+     * Get URI Bluetooth metadata
+     *
+     * @param bluetoothDevice the BluetoothDevice to get metadata
+     * @param key key value within the list of BluetoothDevice.METADATA_*
+     * @return the URI metdata
+     */
+    public static Uri getUriMetaData(BluetoothDevice bluetoothDevice, int key) {
+        String data = getStringMetaData(bluetoothDevice, key);
+        if (data == null) {
+            return null;
+        }
+        return Uri.parse(data);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 2405666..ff34578 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -881,16 +881,12 @@
         //when profile is connected, information would be available
         if (profileConnected) {
             // Update Meta data for connected device
-            if (Boolean.parseBoolean(
-                    mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))) {
-                try {
-                    leftBattery = Integer.parseInt(
-                            mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY));
-                    rightBattery = Integer.parseInt(mDevice.getMetadata(
-                                    BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY));
-                } catch (NumberFormatException e) {
-                    Log.d(TAG, "Parse error for unthethered battery level.");
-                }
+            if (BluetoothUtils.getBooleanMetaData(
+                    mDevice, BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) {
+                leftBattery = BluetoothUtils.getIntMetaData(mDevice,
+                        BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY);
+                rightBattery = BluetoothUtils.getIntMetaData(mDevice,
+                        BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY);
             }
 
             // Set default string with battery level in device connected situation.
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 530c73a..fb5c16b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -19,6 +19,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.PowerManager;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -33,7 +34,25 @@
 public class BatterySaverUtils {
 
     private static final String TAG = "BatterySaverUtils";
-    public static final String EXTRA_CONFIRM_ONLY = "extra_confirm_only";
+    /**
+     * When set to "true" the notification will be a generic confirm message instead of asking the
+     * user if they want to turn on battery saver. If set to false the dialog will specifically
+     * talk about turning on battery saver and provide a button for taking the action.
+     */
+    public static final String EXTRA_CONFIRM_TEXT_ONLY = "extra_confirm_only";
+    /**
+     * Ignored if {@link #EXTRA_CONFIRM_TEXT_ONLY} is "false". Can be set to any of the values in
+     * {@link PowerManager.AutoPowerSaveModeTriggers}. If set the dialog will set the power
+     * save mode trigger to the specified value after the user acknowledges the trigger.
+     */
+    public static final String EXTRA_POWER_SAVE_MODE_TRIGGER = "extra_power_save_mode_trigger";
+    /**
+     * Ignored if {@link #EXTRA_CONFIRM_TEXT_ONLY} is "false". can be set to any value between
+     * 0-100 that will be used if {@link #EXTRA_POWER_SAVE_MODE_TRIGGER} is
+     * {@link PowerManager#POWER_SAVE_MODE_TRIGGER_PERCENTAGE}.
+     */
+    public static final String EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL =
+            "extra_power_save_mode_trigger_level";
 
     private BatterySaverUtils() {
     }
@@ -98,7 +117,10 @@
         }
         final ContentResolver cr = context.getContentResolver();
 
-        if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context, false)) {
+        final Bundle confirmationExtras = new Bundle(1);
+        confirmationExtras.putBoolean(EXTRA_CONFIRM_TEXT_ONLY, false);
+        if (enable && needFirstTimeWarning
+                && maybeShowBatterySaverConfirmation(context, confirmationExtras)) {
             return false;
         }
         if (enable && !needFirstTimeWarning) {
@@ -118,7 +140,7 @@
                         && Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0
                         && Secure.getInt(cr,
                         Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) {
-                    showAutoBatterySaverSuggestion(context, false);
+                    showAutoBatterySaverSuggestion(context, confirmationExtras);
                 }
             }
 
@@ -129,34 +151,36 @@
 
     /**
      * Shows the battery saver confirmation warning if it hasn't been acknowledged by the user in
-     * the past before. When confirmOnly is true, the dialog will have generic info about battery
-     * saver but will only update that the user has been shown the notification and take no
-     * further action. if confirmOnly is false it will show a more specific version of the dialog
-     * that toggles battery saver when acknowledged
+     * the past before. Various extras can be provided that will change the behavior of this
+     * notification as well as the ui for it.
      * @param context A valid context
-     * @param confirmOnly Whether to show the actionless generic dialog (true) or the specific one
-     * that toggles battery saver (false)
+     * @param extras Any extras to include in the intent to trigger this confirmation that will
+     * help the system disambiguate what to show/do
+     *
      * @return True if it showed the notification because it has not been previously acknowledged.
+     * @see #EXTRA_CONFIRM_TEXT_ONLY
+     * @see #EXTRA_POWER_SAVE_MODE_TRIGGER
+     * @see #EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL
      */
-    public static boolean maybeShowBatterySaverConfirmation(Context context, boolean confirmOnly) {
+    public static boolean maybeShowBatterySaverConfirmation(Context context, Bundle extras) {
         if (Secure.getInt(context.getContentResolver(),
                 Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
             return false; // Already shown.
         }
         context.sendBroadcast(
-                getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, confirmOnly));
+                getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, extras));
         return true;
     }
 
-    private static void showAutoBatterySaverSuggestion(Context context, boolean confirmOnly) {
-        context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION, confirmOnly));
+    private static void showAutoBatterySaverSuggestion(Context context, Bundle extras) {
+        context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION, extras));
     }
 
-    private static Intent getSystemUiBroadcast(String action, boolean confirmOnly) {
+    private static Intent getSystemUiBroadcast(String action, Bundle extras) {
         final Intent i = new Intent(action);
         i.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         i.setPackage(SYSUI_PACKAGE);
-        i.putExtra(EXTRA_CONFIRM_ONLY, confirmOnly);
+        i.putExtras(extras);
         return i;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
index 74057be..ff40d8e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
@@ -20,14 +20,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
 import android.location.SettingInjectorService;
 import android.os.Bundle;
 import android.os.Handler;
@@ -37,9 +35,9 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AttributeSet;
-import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.util.Xml;
 
@@ -56,8 +54,8 @@
 import java.util.ArrayList;
 import java.util.Deque;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -157,22 +155,8 @@
      * Adds the InjectedSetting information to a Preference object
      */
     private void populatePreference(Preference preference, InjectedSetting setting) {
-        final PackageManager pm = mContext.getPackageManager();
-        Drawable appIcon = null;
-        try {
-            final PackageItemInfo itemInfo = new PackageItemInfo();
-            itemInfo.icon = setting.iconId;
-            itemInfo.packageName = setting.packageName;
-            final ApplicationInfo appInfo = pm.getApplicationInfo(setting.packageName,
-                    PackageManager.GET_META_DATA);
-            appIcon = IconDrawableFactory.newInstance(mContext)
-                    .getBadgedIcon(itemInfo, appInfo, setting.mUserHandle.getIdentifier());
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.e(TAG, "Can't get ApplicationInfo for " + setting.packageName, e);
-        }
         preference.setTitle(setting.title);
         preference.setSummary(R.string.loading_injected_setting_summary);
-        preference.setIcon(appIcon);
         preference.setOnPreferenceClickListener(new ServiceSettingClickedListener(setting));
     }
 
@@ -182,13 +166,15 @@
      * @param profileId Identifier of the user/profile to obtain the injected settings for or
      *                  UserHandle.USER_CURRENT for all profiles associated with current user.
      */
-    public List<Preference> getInjectedSettings(Context prefContext, final int profileId) {
+    public Map<Integer, List<Preference>> getInjectedSettings(Context prefContext,
+            final int profileId) {
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         final List<UserHandle> profiles = um.getUserProfiles();
-        ArrayList<Preference> prefs = new ArrayList<>();
+        final ArrayMap<Integer, List<Preference>> result = new ArrayMap<>();
         mSettings.clear();
         for (UserHandle userHandle : profiles) {
             if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
+                final List<Preference> prefs = new ArrayList<>();
                 Iterable<InjectedSetting> settings = getSettings(userHandle);
                 for (InjectedSetting setting : settings) {
                     Preference preference = createPreference(prefContext, setting);
@@ -196,12 +182,14 @@
                     prefs.add(preference);
                     mSettings.add(new Setting(setting, preference));
                 }
+                if (!prefs.isEmpty()) {
+                    result.put(userHandle.getIdentifier(), prefs);
+                }
             }
         }
 
         reloadStatusMessages();
-
-        return prefs;
+        return result;
     }
 
     /**
@@ -303,28 +291,6 @@
     }
 
     /**
-     * Checks wheteher there is any preference that other apps have injected.
-     *
-     * @param profileId Identifier of the user/profile to obtain the injected settings for or
-     *                  UserHandle.USER_CURRENT for all profiles associated with current user.
-     */
-    public boolean hasInjectedSettings(final int profileId) {
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        final List<UserHandle> profiles = um.getUserProfiles();
-        final int profileCount = profiles.size();
-        for (int i = 0; i < profileCount; ++i) {
-            final UserHandle userHandle = profiles.get(i);
-            if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
-                Iterable<InjectedSetting> settings = getSettings(userHandle);
-                for (InjectedSetting setting : settings) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
      * Reloads the status messages for all the preference items.
      */
     public void reloadStatusMessages() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 2711e31..3a53d29 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
@@ -47,7 +48,9 @@
 
     @Override
     public String getSummary() {
-        return mCachedDevice.getConnectionSummary();
+        return isConnected() || mCachedDevice.isBusy()
+                ? mCachedDevice.getConnectionSummary()
+                : mContext.getString(R.string.bluetooth_disconnected);
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 8a88a4c..1976ec4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -184,6 +184,7 @@
     private static final int PSK_WPA = 1;
     private static final int PSK_WPA2 = 2;
     private static final int PSK_WPA_WPA2 = 3;
+    private static final int PSK_SAE = 4;
 
     /**
      * The number of distinct wifi levels.
@@ -764,7 +765,7 @@
             ssid = bestResult.SSID;
             bssid = bestResult.BSSID;
             security = getSecurity(bestResult);
-            if (security == SECURITY_PSK) {
+            if (security == SECURITY_PSK || security == SECURITY_SAE) {
                 pskType = getPskType(bestResult);
             }
             mIsCarrierAp = bestResult.isCarrierAp;
@@ -826,8 +827,13 @@
                 return concise ? context.getString(R.string.wifi_security_short_wep) :
                     context.getString(R.string.wifi_security_wep);
             case SECURITY_SAE:
-                return concise ? context.getString(R.string.wifi_security_short_sae) :
-                    context.getString(R.string.wifi_security_sae);
+                if (pskType == PSK_SAE) {
+                    return concise ? context.getString(R.string.wifi_security_short_psk_sae) :
+                            context.getString(R.string.wifi_security_psk_sae);
+                } else {
+                    return concise ? context.getString(R.string.wifi_security_short_sae) :
+                            context.getString(R.string.wifi_security_sae);
+                }
             case SECURITY_OWE:
                 return concise ? context.getString(R.string.wifi_security_short_owe) :
                     context.getString(R.string.wifi_security_owe);
@@ -1460,15 +1466,22 @@
 
     private static int getPskType(ScanResult result) {
         boolean wpa = result.capabilities.contains("WPA-PSK");
-        boolean wpa2 = result.capabilities.contains("WPA2-PSK");
-        if (wpa2 && wpa) {
+        boolean wpa2 = result.capabilities.contains("RSN-PSK");
+        boolean wpa3TransitionMode = result.capabilities.contains("PSK+SAE");
+        boolean wpa3 = result.capabilities.contains("RSN-SAE");
+        if (wpa3TransitionMode) {
+            return PSK_SAE;
+        } else if (wpa2 && wpa) {
             return PSK_WPA_WPA2;
         } else if (wpa2) {
             return PSK_WPA2;
         } else if (wpa) {
             return PSK_WPA;
         } else {
-            Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
+            if (!wpa3) {
+                // Suppress warning for WPA3 only networks
+                Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
+            }
             return PSK_UNKNOWN;
         }
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index b228cf7..3a95852c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -25,6 +25,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.util.Pair;
 
 import com.android.settingslib.widget.AdaptiveIcon;
@@ -47,6 +48,9 @@
     private BluetoothDevice mBluetoothDevice;
 
     private Context mContext;
+    private static final String STRING_METADATA = "string_metadata";
+    private static final String BOOL_METADATA = "true";
+    private static final String INT_METADATA = "25";
 
     @Before
     public void setUp() {
@@ -78,7 +82,7 @@
     @Test
     public void getBtRainbowDrawableWithDescription_normalHeadset_returnAdaptiveIcon() {
         when(mBluetoothDevice.getMetadata(
-                BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn("false");
+                BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn("false".getBytes());
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mCachedBluetoothDevice.getAddress()).thenReturn("1f:aa:bb");
 
@@ -86,4 +90,64 @@
                 RuntimeEnvironment.application,
                 mCachedBluetoothDevice).first).isInstanceOf(AdaptiveIcon.class);
     }
-}
\ No newline at end of file
+
+    @Test
+    public void getStringMetaData_hasMetaData_getCorrectMetaData() {
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON)).thenReturn(
+                STRING_METADATA.getBytes());
+
+        assertThat(BluetoothUtils.getStringMetaData(mBluetoothDevice,
+                BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON)).isEqualTo(STRING_METADATA);
+    }
+
+    @Test
+    public void getIntMetaData_hasMetaData_getCorrectMetaData() {
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(
+                INT_METADATA.getBytes());
+
+        assertThat(BluetoothUtils.getIntMetaData(mBluetoothDevice,
+                BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY))
+                .isEqualTo(Integer.parseInt(INT_METADATA));
+    }
+
+    @Test
+    public void getIntMetaData_invalidMetaData_getErrorCode() {
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(null);
+
+        assertThat(BluetoothUtils.getIntMetaData(mBluetoothDevice,
+                BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON))
+                .isEqualTo(BluetoothUtils.META_INT_ERROR);
+    }
+
+    @Test
+    public void getBooleanMetaData_hasMetaData_getCorrectMetaData() {
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+                BOOL_METADATA.getBytes());
+
+        assertThat(BluetoothUtils.getBooleanMetaData(mBluetoothDevice,
+                BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).isEqualTo(true);
+    }
+
+    @Test
+    public void getUriMetaData_hasMetaData_getCorrectMetaData() {
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_MAIN_ICON)).thenReturn(
+                STRING_METADATA.getBytes());
+
+        assertThat(BluetoothUtils.getUriMetaData(mBluetoothDevice,
+                BluetoothDevice.METADATA_MAIN_ICON)).isEqualTo(Uri.parse(STRING_METADATA));
+    }
+
+    @Test
+    public void getUriMetaData_nullMetaData_getNullUri() {
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_MAIN_ICON)).thenReturn(null);
+
+        assertThat(BluetoothUtils.getUriMetaData(mBluetoothDevice,
+                BluetoothDevice.METADATA_MAIN_ICON)).isNull();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 79b84b9..c0a1f11 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -455,12 +455,12 @@
         updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
-        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
-                "true");
-        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
-                TWS_BATTERY_LEFT);
-        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
-                TWS_BATTERY_RIGHT);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+                "true".getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(
+                TWS_BATTERY_LEFT.getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn(
+                TWS_BATTERY_RIGHT.getBytes());
 
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 "Active, L: 15% battery, R: 25% battery");
@@ -472,12 +472,12 @@
         updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
-                "true");
-        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
-                TWS_BATTERY_LEFT);
-        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
-                TWS_BATTERY_RIGHT);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+                "true".getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(
+                TWS_BATTERY_LEFT.getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn(
+                TWS_BATTERY_RIGHT.getBytes());
 
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 "L: 15% battery, R: 25% battery");
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d1b7c75..314b74a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -154,6 +154,7 @@
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
     <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+    <uses-permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
     <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <!-- Permission needed to enable/disable overlays -->
@@ -194,6 +195,9 @@
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
     <uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT" />
 
+    <!-- Permission required to test ContentResolver caching. -->
+    <uses-permission android:name="android.permission.CACHE_CONTENT" />
+
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fcf9200..02d826f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -175,6 +175,9 @@
     <!-- Adding Quick Settings tiles -->
     <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
 
+    <!-- Quick Settings tile: Night Mode / Dark Theme -->
+    <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
+
     <!-- Block notifications inline notifications -->
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
 
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
index cec97ab..79c691c 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
@@ -87,13 +87,13 @@
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import java.io.FileDescriptor;
@@ -370,8 +370,7 @@
         MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
 
         // Getting system scrim colors ignoring wallpaper visibility since it should never be grey.
-        ColorExtractor.GradientColors systemColors = mColorExtractor.getColors(
-                ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true);
+        ColorExtractor.GradientColors systemColors = mColorExtractor.getNeutralColors();
         // We don't want to interpolate colors because we're defining the initial state.
         // Gradient should be set/ready when you open "Recents".
         mRecentsView.setScrimColors(systemColors, false);
@@ -397,9 +396,7 @@
         if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
             // Recents doesn't care about the wallpaper being visible or not, it always
             // wants to scrim with wallpaper colors
-            ColorExtractor.GradientColors colors = mColorExtractor.getColors(
-                    WallpaperManager.FLAG_SYSTEM,
-                    ColorExtractor.TYPE_DARK, true /* ignoreVis */);
+            ColorExtractor.GradientColors colors = mColorExtractor.getNeutralColors();
             boolean darkText = colors.supportsDarkText();
             if (darkText != mUsingDarkText) {
                 mUsingDarkText = darkText;
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
index 8723fb9..e60ffba 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
@@ -34,7 +34,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.os.IRemoteCallback;
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -50,7 +49,7 @@
 import android.widget.TextView;
 
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
@@ -87,9 +86,9 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -134,7 +133,7 @@
     private int mDividerSize;
 
     private float mBusynessFactor;
-    private GradientDrawable mBackgroundScrim;
+    private ScrimDrawable mBackgroundScrim;
     private ColorDrawable mMultiWindowBackgroundScrim;
     private ValueAnimator mBackgroundScrimAnimator;
     private Point mTmpDisplaySize = new Point();
@@ -172,7 +171,7 @@
         mDividerSize = ssp.getDockedDividerSize(context);
         mTouchHandler = new RecentsViewTouchHandler(this);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
-        mBackgroundScrim = new GradientDrawable(context);
+        mBackgroundScrim = new ScrimDrawable();
         mMultiWindowBackgroundScrim = new ColorDrawable();
 
         LayoutInflater inflater = LayoutInflater.from(context);
@@ -395,7 +394,7 @@
      * @param animated Interpolate colors if true.
      */
     public void setScrimColors(ColorExtractor.GradientColors scrimColors, boolean animated) {
-        mBackgroundScrim.setColors(scrimColors, animated);
+        mBackgroundScrim.setColor(scrimColors.getMainColor(), animated);
         int alpha = mMultiWindowBackgroundScrim.getAlpha();
         mMultiWindowBackgroundScrim.setColor(scrimColors.getMainColor());
         mMultiWindowBackgroundScrim.setAlpha(alpha);
@@ -467,7 +466,6 @@
         // Needs to know the screen size since the gradient never scales up or down
         // even when bounds change.
         mContext.getDisplay().getRealSize(mTmpDisplaySize);
-        mBackgroundScrim.setScreenSize(mTmpDisplaySize.x, mTmpDisplaySize.y);
         mBackgroundScrim.setBounds(left, top, right, bottom);
         mMultiWindowBackgroundScrim.setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
index fbd863d..bc6547f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -59,15 +59,17 @@
         public static final int TYPE_WAKE_DISPLAY = 2;
         public static final int TYPE_SWIPE = 3;
 
-        int mType;
-
-        public int getType() {
-            return mType;
-        }
+        private int mType;
 
         public Sensor(int type) {
             mType = type;
         }
+        public int getType() {
+            return mType;
+        }
+        public String toString() {
+            return "{PluginSensor type=\"" + mType + "\"}";
+        }
     }
 
     /**
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 42600c1..834f4fc 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -117,6 +117,7 @@
         public String expandedAccessibilityClassName;
         public SlashState slash;
         public boolean handlesLongClick = true;
+        public boolean showRippleEffect = true;
 
         public boolean copyTo(State other) {
             if (other == null) throw new IllegalArgumentException();
@@ -135,7 +136,8 @@
                     || !Objects.equals(other.isTransient, isTransient)
                     || !Objects.equals(other.dualTarget, dualTarget)
                     || !Objects.equals(other.slash, slash)
-                    || !Objects.equals(other.handlesLongClick, handlesLongClick);
+                    || !Objects.equals(other.handlesLongClick, handlesLongClick)
+                    || !Objects.equals(other.showRippleEffect, showRippleEffect);
             other.icon = icon;
             other.iconSupplier = iconSupplier;
             other.label = label;
@@ -149,6 +151,7 @@
             other.isTransient = isTransient;
             other.slash = slash != null ? slash.copy() : null;
             other.handlesLongClick = handlesLongClick;
+            other.showRippleEffect = showRippleEffect;
             return changed;
         }
 
diff --git a/packages/SystemUI/res-keyguard/layout/type_aod_clock.xml b/packages/SystemUI/res-keyguard/layout/type_aod_clock.xml
deleted file mode 100644
index 28ff5a2..0000000
--- a/packages/SystemUI/res-keyguard/layout/type_aod_clock.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2019 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-<com.android.keyguard.clock.ClockLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-  >
-  <include layout="@layout/typographic_clock" />
-</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/typographic_clock.xml b/packages/SystemUI/res-keyguard/layout/typographic_clock.xml
deleted file mode 100644
index 73bb4b9..0000000
--- a/packages/SystemUI/res-keyguard/layout/typographic_clock.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2019 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-<com.android.keyguard.clock.TypographicClock
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/type_clock"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:paddingStart="50dp"
-    android:textAlignment="viewStart"
-    style="@style/widget_big"
-    android:textSize="40dp"
-    />
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index d07caa5..6836f1e 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -169,13 +169,66 @@
     <item msgid="2233497913571137419">"പത്ത്"</item>
     <item msgid="5621554266768657830">"പതിനൊന്ന്"</item>
   </string-array>
-    <!-- no translation found for type_clock_minutes:1 (2091812961809760681) -->
-    <!-- no translation found for type_clock_minutes:2 (1496435384877290709) -->
-    <!-- no translation found for type_clock_minutes:3 (881846472976674129) -->
-    <!-- no translation found for type_clock_minutes:4 (2784477043911540584) -->
-    <!-- no translation found for type_clock_minutes:5 (1610928853656700614) -->
-    <!-- no translation found for type_clock_minutes:6 (2317806244043886658) -->
-    <!-- no translation found for type_clock_minutes:7 (3318687539120971327) -->
-    <!-- no translation found for type_clock_minutes:8 (5701600693712102348) -->
-    <!-- no translation found for type_clock_minutes:9 (3247381605947372495) -->
+  <string-array name="type_clock_minutes">
+    <item msgid="8322049385467207985">"മണി"</item>
+    <item msgid="2091812961809760681">"ഓ ഒരു മിനിറ്റ്"</item>
+    <item msgid="1496435384877290709">"ഓ രണ്ട് മിനിറ്റ്"</item>
+    <item msgid="881846472976674129">"ഓ മൂന്ന് മിനിറ്റ്"</item>
+    <item msgid="2784477043911540584">"ഓ നാലു മിനിറ്റ്"</item>
+    <item msgid="1610928853656700614">"ഓ അഞ്ച് മിനിറ്റ്"</item>
+    <item msgid="2317806244043886658">"ഓ ആറ് മിനിറ്റ്"</item>
+    <item msgid="3318687539120971327">"ഓ ഏഴ് മിനിറ്റ്"</item>
+    <item msgid="5701600693712102348">"ഓ എട്ട് മിനിറ്റ്"</item>
+    <item msgid="3247381605947372495">"ഓ ഒമ്പത് മിനിറ്റ്"</item>
+    <item msgid="3508406095411245038">"പത്ത്"</item>
+    <item msgid="7161996337755311711">"പതിനൊന്ന്"</item>
+    <item msgid="4044549963329624197">"പന്ത്രണ്ട്"</item>
+    <item msgid="333373157917379088">"പതിമൂന്ന്"</item>
+    <item msgid="2631202907124819385">"പതിനാല്"</item>
+    <item msgid="6472396076858033453">"പതിനഞ്ച്"</item>
+    <item msgid="8656981856181581643">"പതിനാറ്"</item>
+    <item msgid="7289026608562030619">"പതിനേഴ്"</item>
+    <item msgid="3881477602692646573">"പതിനെട്ട്"</item>
+    <item msgid="3358129827772984226">"പത്തൊമ്പത്"</item>
+    <item msgid="3308575407402865807">"ഇരുപത്"</item>
+    <item msgid="5346560955382229629">"ഇരുപത്തിയൊന്ന്\n"</item>
+    <item msgid="226750304761473436">"ഇരുപത്തിരണ്ട്\n"</item>
+    <item msgid="616811325336838734">"ഇരുപത്തിമൂന്ന്\n"</item>
+    <item msgid="616346116869053440">"ഇരുപത്തിനാല്\n"</item>
+    <item msgid="4642996410384042830">"ഇരുപത്തിയഞ്ച്\n"</item>
+    <item msgid="7506092849993571465">"ഇരുപത്തിയാറ്\n"</item>
+    <item msgid="1915078191101042031">"ഇരുപത്തിയേഴ്\n"</item>
+    <item msgid="4292378641900520252">"ഇരുപത്തിയെട്ട്\n"</item>
+    <item msgid="5339513901773103696">"ഇരുപത്തിയൊമ്പത്\n"</item>
+    <item msgid="3574673250891657607">"മുപ്പത്"</item>
+    <item msgid="5796923836589110940">"മുപ്പത്തിയൊന്ന്\n"</item>
+    <item msgid="5859323597571702052">"മുപ്പത്തിരണ്ട്\n"</item>
+    <item msgid="5133326723148876507">"മുപ്പത്തിമൂന്ന്\n"</item>
+    <item msgid="2693999494655663096">"മുപ്പത്തിനാല്\n"</item>
+    <item msgid="3316754944962836197">"അമ്പത്തിയഞ്ച്\n"</item>
+    <item msgid="816891008836796723">"മുപ്പത്തിയാറ്\n"</item>
+    <item msgid="9158890488666520078">"മുപ്പത്തിയേഴ്\n"</item>
+    <item msgid="1894769703213894011">"മുപ്പത്തിയെട്ട്\n"</item>
+    <item msgid="5638820345598572399">"മുപ്പത്തിയൊമ്പത്\n"</item>
+    <item msgid="8838304023017895439">"നാൽപത്"</item>
+    <item msgid="1834742948932559597">"നാൽപ്പത്തിയൊന്ന്\n"</item>
+    <item msgid="6573707308847773944">"നാൽപത്തിരണ്ട്\n"</item>
+    <item msgid="2450149950652678001">"നാൽപ്പത്തിമൂന്ന്\n"</item>
+    <item msgid="2874667401318178036">"നാൽപത്തിനാല്\n"</item>
+    <item msgid="3391101532763048862">"നാൽപത്തിയഞ്ച്\n"</item>
+    <item msgid="1671489330863254362">"നാൽപ്പത്തിയാറ്\n"</item>
+    <item msgid="5916017359554531038">"നാൽപത്തിയേഴ്\n"</item>
+    <item msgid="8205413177993059967">"നാൽപത്തിയെട്ട്\n"</item>
+    <item msgid="6607867415142171302">"നാൽപത്തിയൊമ്പത്\n"</item>
+    <item msgid="8358850748472089162">"അമ്പത്"</item>
+    <item msgid="3551313125255080234">"അമ്പത്തിയൊന്ന്\n"</item>
+    <item msgid="1559678130725716542">"അമ്പത്തിരണ്ട്\n"</item>
+    <item msgid="431441994725492377">"അമ്പത്തിമൂന്ന്\n"</item>
+    <item msgid="6345774640539623024">"അമ്പത്തിനാല്\n"</item>
+    <item msgid="8018192990793931120">"അമ്പത്തിയഞ്ച്\n"</item>
+    <item msgid="6187650843754604534">"അമ്പത്തിയാറ്\n"</item>
+    <item msgid="8727240174015993259">"അമ്പത്തിയേഴ്\n"</item>
+    <item msgid="848339003778952950">"അമ്പത്തിയെട്ട്\n"</item>
+    <item msgid="5798985802835423618">"അമ്പത്തിയൊമ്പത്\n"</item>
+  </string-array>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index bfceb15..6baa8c4 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -69,7 +69,7 @@
       <item quantity="other">ลองอีกครั้งใน <xliff:g id="NUMBER">%d</xliff:g> วินาที</item>
       <item quantity="one">ลองอีกครั้งใน 1 วินาที</item>
     </plurals>
-    <string name="kg_pattern_instructions" msgid="5547646893001491340">"วาดรูปแบบของคุณ"</string>
+    <string name="kg_pattern_instructions" msgid="5547646893001491340">"ลากรูปแบบของคุณ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"ป้อน PIN ของซิม"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"ป้อน PIN ของซิมสำหรับ \"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string>
     <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> ปิดใช้ eSIM เพื่อใช้อุปกรณ์โดยไม่มีบริการมือถือ"</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 2f2f84a..4738887 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -405,106 +405,6 @@
 number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
     </plurals>
 
-    <!-- Time displayed on typographic clock face, which displays the time in words.
-             Example:
-
-                 It's
-                 Four
-                 Twenty
-                 Nine
-
-         This string requires two arguments: the first in the hours of the time and
-         the second is the minutes of the time. The hours string is obtained from
-         string-array type_clock_hours below and the minutes string is obtained
-         from string-array type_clock_minutes below.
-
-    [CHAR LIMIT=8] -->
-    <plurals name="type_clock_header">
-        <item quantity="one"><annotation name="color">It\u2019s</annotation>\n^1\n^2</item>
-        <item quantity="few"><annotation name="color">It\u2019s</annotation>\n^1\n^2</item>
-        <item quantity="other"><annotation name="color">It\u2019s</annotation>\n^1\n^2</item>
-    </plurals>
-
-    <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=12] -->
-    <string-array name="type_clock_hours">
-        <item>Twelve</item>
-        <item>One</item>
-        <item>Two</item>
-        <item>Three</item>
-        <item>Four</item>
-        <item>Five</item>
-        <item>Six</item>
-        <item>Seven</item>
-        <item>Eight</item>
-        <item>Nine</item>
-        <item>Ten</item>
-        <item>Eleven</item>
-    </string-array>
-
-    <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=20] -->
-    <string-array name="type_clock_minutes">
-        <item>O\u2019Clock</item>
-        <item>Oh One</item>
-        <item>Oh Two</item>
-        <item>Oh Three</item>
-        <item>Oh Four</item>
-        <item>Oh Five</item>
-        <item>Oh Six</item>
-        <item>Oh Seven</item>
-        <item>Oh Eight</item>
-        <item>Oh Nine</item>
-        <item>Ten</item>
-        <item>Eleven</item>
-        <item>Twelve</item>
-        <item>Thirteen</item>
-        <item>Fourteen</item>
-        <item>Fifteen</item>
-        <item>Sixteen</item>
-        <item>Seventeen</item>
-        <item>Eighteen</item>
-        <item>Nineteen</item>
-        <item>Twenty</item>
-        <item>Twenty\nOne</item>
-        <item>Twenty\nTwo</item>
-        <item>Twenty\nThree</item>
-        <item>Twenty\nFour</item>
-        <item>Twenty\nFive</item>
-        <item>Twenty\nSix</item>
-        <item>Twenty\nSeven</item>
-        <item>Twenty\nEight</item>
-        <item>Twenty\nNine</item>
-        <item>Thirty</item>
-        <item>Thirty\nOne</item>
-        <item>Thirty\nTwo</item>
-        <item>Thirty\nThree</item>
-        <item>Thirty\nFour</item>
-        <item>Thirty\nFive</item>
-        <item>Thirty\nSix</item>
-        <item>Thirty\nSeven</item>
-        <item>Thirty\nEight</item>
-        <item>Thirty\nNine</item>
-        <item>Forty</item>
-        <item>Forty\nOne</item>
-        <item>Forty\nTwo</item>
-        <item>Forty\nThree</item>
-        <item>Forty\nFour</item>
-        <item>Forty\nFive</item>
-        <item>Forty\nSix</item>
-        <item>Forty\nSeven</item>
-        <item>Forty\nEight</item>
-        <item>Forty\nNine</item>
-        <item>Fifty</item>
-        <item>Fifty\nOne</item>
-        <item>Fifty\nTwo</item>
-        <item>Fifty\nThree</item>
-        <item>Fifty\nFour</item>
-        <item>Fifty\nFive</item>
-        <item>Fifty\nSix</item>
-        <item>Fifty\nSeven</item>
-        <item>Fifty\nEight</item>
-        <item>Fifty\nNine</item>
-    </string-array>
-
     <!-- Title for default clock face that will appear in the picker app next to a preview image of
          the clock face. [CHAR LIMIT=8] -->
     <string name="clock_title_default" translatable="false">Default</string>
diff --git a/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
new file mode 100644
index 0000000..fe1bb26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
@@ -0,0 +1,31 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="22"
+    android:viewportHeight="17"
+    android:width="22dp"
+    android:height="17dp">
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M1.22,8.49l0.43-4.96h4.33v1.17H2.67L2.44,7.41c0.41-0.29,0.85-0.43,1.33-0.43c0.77,0,1.38,0.3,1.83,0.9 s0.66,1.41,0.66,2.43c0,1.03-0.24,1.84-0.72,2.43s-1.14,0.88-1.98,0.88c-0.75,0-1.36-0.24-1.83-0.73s-0.74-1.16-0.81-2.02h1.13 c0.07,0.57,0.23,1,0.49,1.29c0.26,0.29,0.59,0.43,1.01,0.43c0.47,0,0.84-0.2,1.1-0.61c0.26-0.41,0.4-0.96,0.4-1.65 c0-0.65-0.14-1.18-0.43-1.59S3.96,8.11,3.47,8.11c-0.4,0-0.72,0.1-0.96,0.31L2.19,8.75L1.22,8.49z" />
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M14.14,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13c0.56-0.7,1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79c0.54,0.53,0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45c-0.29-0.35-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7C9.14,5.63,8.96,6.37,8.95,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M20.96,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back.xml b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
index 1448843..ee40262 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="28dp"
     android:height="28dp"
+    android:autoMirrored="true"
     android:viewportWidth="28"
     android:viewportHeight="28">
 
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
index 93b2f9c8..442fafc 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="28dp"
     android:height="28dp"
+    android:autoMirrored="true"
     android:viewportWidth="28"
     android:viewportHeight="28">
     <path
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index d033057..7a43c6d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -47,6 +47,7 @@
         android:layout_height="match_parent"
         android:paddingStart="@dimen/status_bar_padding_start"
         android:paddingEnd="@dimen/status_bar_padding_end"
+        android:paddingTop="@dimen/status_bar_padding_top"
         android:orientation="horizontal"
         >
         <FrameLayout
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 895192a..baca541 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index b2e68c2..e325044 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5ጂ"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5ጂ+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index cda4def..876609e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"شبكة الجيل الرابع أو أحدث"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+‎"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"‏شبكة 5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"‏شبكة 5G‎ والأحدث"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 6d09133..4b1db9d 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"এলটিই"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"এলটিই+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -277,8 +279,7 @@
       <item quantity="one"> ভিতৰত আৰু <xliff:g id="NUMBER_1">%s</xliff:g>টা জাননী আছে।</item>
       <item quantity="other"> ভিতৰত আৰু <xliff:g id="NUMBER_1">%s</xliff:g>টা জাননী আছে।</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"জাননীৰ ছেটিংসমূহ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ছেটিংসমূহ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"আপোনাৰ ফ\'নৰ স্ক্ৰীণ স্বয়ংক্ৰিয়ভাৱে ঘূৰিব৷"</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"এই জাননীবোৰে আপোনাক সতৰ্ক কৰিব"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"আপুনি সাধাৰণতে এই জাননীসমূহ অগ্ৰাহ্য কৰে। \nসেইবোৰ দেখুওৱাই থাকিব লাগিবনে?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"কৰা হ’ল"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"প্ৰয়োগ কৰক"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"এই জাননীসমূহ দেখুওৱাই থাকিব লাগিবনে?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"জাননী বন্ধ কৰক"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"নিৰৱে ডেলিভাৰ কৰক"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"অৱৰোধ কৰক"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"দেখুওৱাই থাকক"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"সৰু কৰক"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"মৃদু"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"নীৰৱ হৈ থাকক"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"বাধা দিয়া"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"সতৰ্ক কৰি থাকক"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"জাননী অফ কৰক"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"এই এপটোৰ জাননী দেখুওৱাই থাকিব লাগিবনে?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"অৱৰোধ কৰা জাননী ক’তো দেখা নাযায় বা সেইবোৰে কোনো শব্দ নকৰে। আপুনি ছেটিংসমূহলৈ গৈ জাননীসমূহ অৱৰোধৰ পৰা আঁতৰাব পাৰে৷"</string>
     <string name="hint_text_silent" msgid="859468056340177016">"নিৰৱ জাননীসমূহ শ্বেডত দেখা যায়, কিন্তু লক স্ক্ৰীণত আৰু বেনাৰ হিচাপে দেখা নাযায় আৰু কোনো শব্দ নকৰে।"</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"এই জাননীবোৰে এটা শব্দ কৰিব আৰু জাননী দেৰাজ, স্থিতি দণ্ড আৰু লক স্ক্ৰীণত দেখা যাব"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"এই জাননীসমূহ বন্ধ কৰিব নোৱাৰি"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ জৰিয়তে"</string>
     <string name="appops_camera" msgid="8100147441602585776">"এই এপে কেমেৰা ব্য়ৱহাৰ কৰি আছে।"</string>
     <string name="appops_microphone" msgid="741508267659494555">"এই এপে মাইক্ৰ\'ফ\'ন ব্য়ৱহাৰ কৰি আছে।"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 36c297e..5354e0d 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 00f13cc..242db2e 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -376,7 +377,7 @@
     <string name="recents_quick_scrub_onboarding" msgid="2778062804333285789">"Prevucite udesno da biste brzo promenili aplikacije"</string>
     <string name="quick_step_accessibility_toggle_overview" msgid="7171470775439860480">"Uključi/isključi pregled"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjena je"</string>
-    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Puni se"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do kraja punjenja"</string>
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ne puni se"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se možda\nnadgleda"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 5ff11d7..396c4be 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 7764244..dd6ffb2 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 94b32a8..e8d3d3f 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -277,8 +279,7 @@
       <item quantity="one">ভিতরে আরও <xliff:g id="NUMBER_1">%s</xliff:g>টি বিজ্ঞপ্তি আছে।</item>
       <item quantity="other">ভিতরে আরও <xliff:g id="NUMBER_1">%s</xliff:g>টি বিজ্ঞপ্তি আছে।</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"বিজ্ঞপ্তির সেটিংস"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> সেটিংস"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"স্ক্রিন অটোমেটিক ঘুরে যাবে৷"</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"এই বিজ্ঞপ্তিগুলি আপনাকে সতর্ক করে দেবে"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"এই বিজ্ঞপ্তিগুলিকে আপনি সাধারণত বাতিল করেন। \nসেগুলি দেখতে চান?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"হয়ে গেছে"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"প্রয়োগ করুন"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"এই বিজ্ঞপ্তিগুলি পরেও দেখে যেতে চান?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"বিজ্ঞপ্তি বন্ধ করুন"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"সাইলেন্ট মোডে দেখান"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"ব্লক করুন"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"দেখতে থাকুন"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"ছোট করে দিন"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"সাইলেন্ট মোডে"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"বিজ্ঞপ্তি মিউট করুন"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"বিরক্তিকর"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"বিজ্ঞপ্তি পান"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"বিজ্ঞপ্তি বন্ধ করুন"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"এই অ্যাপের বিজ্ঞপ্তি পরেও দেখে যেতে চান?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"ব্লক করা বিজ্ঞপ্তি কোথাও দেখানো হয় না ও সেটির শব্দ শোনা যায় না। আপনি সেটিংস থেকে বিজ্ঞপ্তি আনব্লক করতে পারেন।"</string>
     <string name="hint_text_silent" msgid="859468056340177016">"নীরব বিজ্ঞপ্তি শেডে দেখানো হয়, কিন্তু লক স্ক্রিনে দেখানো হয় না। একইসাথে, এটি ব্যানার দেখাতে পারে না বা আওয়াজও করতে পারে না।"</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"আওয়াজ হলেই জানতে পারবেন বিজ্ঞপ্তি এসেছে এবং সেটি বিজ্ঞপ্তি ড্রয়ার, স্ট্যাটাস বার এবং লক স্ক্রিনে দেখা যাবে"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"এই বিজ্ঞপ্তিগুলি বন্ধ করা যাবে না"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"এই সমস্ত বিজ্ঞপ্তিকে এখানে কনফিগার করা যাবে না"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর মাধ্যমে"</string>
     <string name="appops_camera" msgid="8100147441602585776">"এই অ্যাপটি ক্যামেরা ব্যবহার করছে।"</string>
     <string name="appops_microphone" msgid="741508267659494555">"এই অ্যাপটি মাইক্রোফোন ব্যবহার করছে।"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index f85ed35..a51ba97 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -817,7 +818,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="5755818559638850294">"Zaključavanje ekrana"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
-    <string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
+    <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiziraj"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
     <string name="pip_phone_settings" msgid="8080777499521528521">"Postavke"</string>
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Povucite prema dolje da odbacite"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ce683ef..fdf51f2 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -604,7 +605,7 @@
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activa"</string>
-    <string name="show_silently" msgid="6841966539811264192">"Mostra les notificacions de manera silenciosa"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Mostra les notificacions en silenci"</string>
     <string name="block" msgid="2734508760962682611">"Bloqueja totes les notificacions"</string>
     <string name="do_not_silence" msgid="6878060322594892441">"No silenciïs"</string>
     <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciïs ni bloquegis"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1ba20c2..924ad5a5 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c861c4f..d347f8e 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c185d1c..fb7628a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -840,7 +841,7 @@
     <string name="lockscreen_unlock_right" msgid="1529992940510318775">"Rechte Verknüpfung entsperrt außerdem"</string>
     <string name="lockscreen_none" msgid="4783896034844841821">"Keine"</string>
     <string name="tuner_launch_app" msgid="1527264114781925348">"<xliff:g id="APP">%1$s</xliff:g> starten"</string>
-    <string name="tuner_other_apps" msgid="4726596850501162493">"Weitere Apps"</string>
+    <string name="tuner_other_apps" msgid="4726596850501162493">"Sonstige Apps"</string>
     <string name="tuner_circle" msgid="2340998864056901350">"Kreis"</string>
     <string name="tuner_plus" msgid="6792960658533229675">"Plus"</string>
     <string name="tuner_minus" msgid="4806116839519226809">"Minus"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c5fc126..ba5e122 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 98d551e..8ea35af 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index d2fac3d..9241670 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 98d551e..8ea35af 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 98d551e..8ea35af 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 2f76dd1..f28f761 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‎‎‎4G+‎‏‎‎‏‎"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎LTE‎‏‎‎‏‎"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‎‎LTE+‎‏‎‎‏‎"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎5Ge‎‏‎‎‏‎"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎5G‎‏‎‎‏‎"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎5G+‎‏‎‎‏‎"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎1X‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 10f49ed..fdee8a8 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 2153ab7..8e620d1 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5G E"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 7df6494..59616ac 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 2c917b6..71a1584 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -38,12 +38,12 @@
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktibatu"</string>
     <string name="battery_saver_start_action" msgid="8187820911065797519">"Aktibatu bateria-aurrezlea"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ezarpenak"</string>
-    <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
+    <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifia"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Biratu pantaila automatikoki"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DESAKTIBATU AUDIOA"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Jakinarazpenak"</string>
-    <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetootha konektatu da"</string>
+    <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-a konektatu da"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfiguratu idazketa-metodoak"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teklatu fisikoa"</string>
     <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string>
@@ -125,8 +125,8 @@
     <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Aurpegiaren ikonoa"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoom-bateragarritasunaren botoia."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Handiagotu pantaila txikia."</string>
-    <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetootha konektatuta."</string>
-    <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetootha deskonektatuta."</string>
+    <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-a konektatuta."</string>
+    <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth-a deskonektatuta."</string>
     <string name="accessibility_no_battery" msgid="358343022352820946">"Ez dago bateriarik."</string>
     <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Bateriak barra bat du."</string>
     <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Bateriak bi barra ditu."</string>
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -295,8 +296,8 @@
     <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarmak soilik"</string>
     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Isiltasun osoa"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth-a"</string>
-    <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetootha (<xliff:g id="NUMBER">%d</xliff:g> gailu)"</string>
-    <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetootha desaktibatuta"</string>
+    <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth-a (<xliff:g id="NUMBER">%d</xliff:g> gailu)"</string>
+    <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth-a desaktibatuta"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Ez dago parekatutako gailurik erabilgarri"</string>
     <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="7106697106764717416">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
     <string name="quick_settings_bluetooth_secondary_label_audio" msgid="5673845963301132071">"Audioa"</string>
@@ -668,7 +669,7 @@
       <item quantity="other">%d minutu</item>
       <item quantity="one">%d minutu</item>
     </plurals>
-    <string name="battery_panel_title" msgid="7944156115535366613">"Bateriaren erabilera"</string>
+    <string name="battery_panel_title" msgid="7944156115535366613">"Bateria-erabilera"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Bateria-aurrezlea ez dago erabilgarri gailua kargatzen ari denean"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Bateria-aurrezlea"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Errendimendua eta atzeko planoko datuen erabilera murrizten ditu"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 9a7d1b7..e673a49 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+‎"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+‎"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 9203a19..512dc5c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6e0bd337..3293f41 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b4cc5bd..f13cdc3 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 62da3b6..17177d8 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -704,7 +706,7 @@
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Volver"</string>
     <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificacións"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atallos de teclado"</string>
-    <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Cambiar de deseño de teclado"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Cambiar deseño do teclado"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicacións"</string>
     <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistente"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 42e1fef..8535a3f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -277,8 +279,7 @@
       <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> વધુ સૂચના અંદર છે.</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> વધુ સૂચના અંદર છે.</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"સૂચનાઓની સેટિંગ્સ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> સેટિંગ્સ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"સ્ક્રીન આપમેળે ફરશે."</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"આ બધા નોટિફિકેશન તમને અલર્ટ કરશે"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"તમે સામાન્ય રીતે આ નોટીફિકેશનને છોડી દો છો. \nતેમને બતાવવાનું ચાલુ રાખીએ?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"થઈ ગયું"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"લાગુ કરો"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"આ નોટિફિકેશન બતાવવાનું ચાલુ રાખીએ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"નોટિફિકેશન બંધ કરો"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"ચુપચાપ મોકલો"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"બ્લૉક કરો"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"બતાવવાનું ચાલુ રાખો"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"નાનું કરો"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"સાઇલન્ટ નોટિફિકેશન"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"સાઇલન્ટ મોડ ચાલુ રાખો"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"વિક્ષેપ કરી શકતા"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"અલર્ટ કરવાનું ચાલુ રાખો"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"નોટિફિકેશન બંધ કરો"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"આ ઍપમાંથી નોટિફિકેશન બતાવવાનું ચાલુ રાખીએ?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"બ્લૉક કરેલાં નોટિફિકેશન ક્યાંય દેખાતાં નથી કે અવાજ સંભળાવતાં નથી. તમે સેટિંગમાં જઈને નોટિફિકેશનને અનબ્લૉક કરી શકો છો."</string>
     <string name="hint_text_silent" msgid="859468056340177016">"સાઇલન્ટ નોટિફિકેશન શેડમાં દેખાય છે, પણ લૉક સ્ક્રીન પર દેખાતાં નથી, બૅનર પ્રસ્તુત કરે છે અથવા ધ્વનિ વગાડે છે."</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"આ બધા નોટિફિકેશન કોઈ સાઉન્ડ વગાડશે અને તે નોટિફિકેશન ડ્રોઅર, સ્ટેટસ બાર તેમજ લૉક સ્ક્રીનમાં પણ દેખાશે"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"આ નોટિફિકેશન બંધ કરી શકશો નહીં"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"નોટિફિકેશનના આ ગ્રૂપની ગોઠવણી અહીં કરી શકાશે નહીં"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> મારફતે"</string>
     <string name="appops_camera" msgid="8100147441602585776">"આ ઍપ કૅમેરાનો ઉપયોગ કરી રહી છે."</string>
     <string name="appops_microphone" msgid="741508267659494555">"આ ઍપ માઇક્રોફોનનો ઉપયોગ કરી રહી છે."</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index cf16179..7d38dd9 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -26,8 +26,8 @@
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाएं"</string>
     <string name="battery_low_title" msgid="9187898087363540349">"बैटरी जल्दी ही खत्म हो जाएगी"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष"</string>
-    <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> बची है, आपके इस्तेमाल करने के तरीके के हिसाब से बैटरी लगभग <xliff:g id="TIME">%2$s</xliff:g> चलेगी"</string>
-    <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> बची है, बैटरी लगभग <xliff:g id="TIME">%2$s</xliff:g> चलेगी"</string>
+    <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> बची है, आपके इस्तेमाल करने के हिसाब से बैटरी करीब <xliff:g id="TIME">%2$s</xliff:g> चलेगी"</string>
+    <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> बची है, बैटरी करीब <xliff:g id="TIME">%2$s</xliff:g> चलेगी"</string>
     <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> बैटरी बची है. बैटरी सेवर चालू है."</string>
     <string name="invalid_charger" msgid="2741987096648693172">"यूएसबी के ज़रिए चार्ज नहीं किया जा सकता. अपने डिवाइस के साथ मिलने वाले चार्जर का इस्तेमाल करें."</string>
     <string name="invalid_charger_title" msgid="2836102177577255404">"यूएसबी के ज़रिए चार्ज नहीं किया जा सकता"</string>
@@ -175,6 +175,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"एलटीई"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -284,8 +286,7 @@
       <item quantity="one">इसमें <xliff:g id="NUMBER_1">%s</xliff:g> और सूचनाएं हैं.</item>
       <item quantity="other">इसमें <xliff:g id="NUMBER_1">%s</xliff:g> और सूचनाएं हैं.</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"सूचना सेटिंग"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिंग"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्‍क्रीन स्‍वचालित रूप से घूमेगी."</string>
@@ -397,7 +398,7 @@
     <string name="zen_silence_introduction" msgid="3137882381093271568">"इससे अलार्म, संगीत, वीडियो और गेम सहित सभी आवाज़ और कंपन (वाइब्रेशन) रोक दिए जाते हैं."</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">"कम अत्यावश्यक सूचनाएं नीचे दी गई हैं"</string>
-    <string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए पुन: टैप करें"</string>
+    <string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए फिर से टैप करें"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string>
     <string name="do_disclosure_generic" msgid="5615898451805157556">"इस डिवाइस का प्रबंधन आपका संगठन करता है"</string>
     <string name="do_disclosure_with_name" msgid="5640615509915445501">"इस डिवाइस के प्रबंधक <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> हैं"</string>
@@ -427,7 +428,7 @@
     <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"अतिथि को निकालें?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"इस सत्र के सभी ऐप्स और डेटा को हटा दिया जाएगा."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"निकालें"</string>
-    <string name="guest_wipe_session_title" msgid="6419439912885956132">"अतिथि, आपका पुन: स्वागत है!"</string>
+    <string name="guest_wipe_session_title" msgid="6419439912885956132">"अतिथि, आपका फिर से स्वागत है!"</string>
     <string name="guest_wipe_session_message" msgid="8476238178270112811">"क्‍या आप अपना सत्र जारी रखना चाहते हैं?"</string>
     <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"फिर से शुरू करें"</string>
     <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"हां, जारी रखें"</string>
@@ -611,7 +612,7 @@
     <string name="activity_not_found" msgid="348423244327799974">"ऐप्लिकेशन आपके डिवाइस पर इंस्टॉल नहीं है"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"घड़ी के सेकंड दिखाएं"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बार में सेकंड में समय दिखाएं. इससे बैटरी लाइफ़ पर असर पड़ सकता है."</string>
-    <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को फिर से व्यवस्थित करें"</string>
     <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
@@ -632,32 +633,26 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"ये सूचनाएं आपको अलर्ट करेंगी"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"अाप अक्सर इन सूचनाओं को खारिज कर देते हैं. \nआगे भी इन्हें देखना जारी रखना चाहते हैं?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"हो गया"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"लागू करें"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ये सूचनाएं दिखाना जारी रखें?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"सूचनाएं दिखाना बंद करें"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"बिना आवाज़ के भेजें"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"ब्लॉक करें"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"दिखाना जारी रखें"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"सूचनाएं छोटी करें"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"बिना आवाज़ के"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"साइलेंट मोड में सूचनाएं पाएं"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"आवाज़ वाली सूचनाएं"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"सूचना देना जारी रखें"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"सूचनाएं बंद करें"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"इस ऐप्लिकेशन से जुड़ी सूचनाएं दिखाना जारी रखें?"</string>
     <!-- no translation found for hint_text_block (3554459167504485284) -->
     <skip />
     <!-- no translation found for hint_text_silent (859468056340177016) -->
     <skip />
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"यह सूचनाएं आवाज़ करेंगी और सूचना की दराज, स्टेटस बार और लॉक स्क्रीन में दिखाई देंगी"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"ये सूचनाएं दिखाया जाना बंद नहीं किया जा सकता"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"सूचनाओं के इस समूह को यहां कॉन्फ़िगर नहीं किया जा सकता"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> के ज़रिए"</string>
     <string name="appops_camera" msgid="8100147441602585776">"यह ऐप्लिकेशन कैमरे का इस्तेमाल कर रहा है."</string>
     <string name="appops_microphone" msgid="741508267659494555">"यह ऐप्लिकेशन माइक्रोफ़ोन का इस्तेमाल कर रहा है."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7018cfd5..c6d9c75 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G i više"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7bc45ea..ef0b84b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -309,7 +310,7 @@
     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Automatikus képernyőforgatás"</string>
     <string name="accessibility_quick_settings_rotation_value" msgid="8187398200140760213">"<xliff:g id="ID_1">%s</xliff:g> mód"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Elforgatás zárolva"</string>
-    <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Álló"</string>
+    <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portré"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Fekvő"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Beviteli módszer"</string>
     <string name="quick_settings_location_label" msgid="5011327048748762257">"Tartózkodási hely"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index a95bbb1..aaf74b4 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 0f8686d..a816f42 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -626,7 +627,7 @@
     <string name="inline_block_button" msgid="8735843688021655065">"Blokir"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Terus tampilkan"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"Perkecil"</string>
-    <string name="inline_silent_button_silent" msgid="6904727667411781466">"Lembut"</string>
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"Senyap"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"Tetap nonaktif"</string>
     <string name="inline_silent_button_alert" msgid="2449191160203602471">"Mengganggu"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"Terus beri tahu"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 54787a2..7a29145 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6c1bf71..d304bed 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a271e6e..f1e5a1c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"+4G"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"+LTE"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"‏+G‏5"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 261c05e..ebe6dcc 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 643e9ff..1b326a1 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index fcb314c..b74aeb1 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -225,8 +227,8 @@
     <string name="accessibility_quick_settings_dnd_none_on" msgid="2960643943620637020">"үнсіз"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"тек дабылдар"</string>
     <string name="accessibility_quick_settings_dnd" msgid="5555155552520665891">"Мазаламау."</string>
-    <string name="accessibility_quick_settings_dnd_changed_off" msgid="2757071272328547807">"Мазаламау режимі өшірілді."</string>
-    <string name="accessibility_quick_settings_dnd_changed_on" msgid="6808220653747701059">"мазаламау режимі қосылды."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="2757071272328547807">"\"Мазаламау\" режимі өшірілді."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="6808220653747701059">"\"Мазаламау\" режимі қосылды."</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth өшірулі."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth қосулы."</string>
@@ -441,8 +443,8 @@
     <string name="battery_saver_notification_title" msgid="8614079794522291840">"Battery saver қосулы"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Өнімділікті және фондық деректерді азайтады"</string>
     <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Battery saver функциясын өшіру"</string>
-    <string name="media_projection_dialog_text" msgid="5751657130671431216">"Жазу және трансляциялау кезінде <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> сіз ойнайтын аудиомазмұн және құпия сөздер, төлем ақпараттары, фотосуреттер және хабарлар сияқты кез келген құпия ақпаратты сақтай аласыз."</string>
-    <string name="media_projection_dialog_title" msgid="8124184308671641248">"Трансляциялау/Жазу кезінде құпия ақпаратты көрсету"</string>
+    <string name="media_projection_dialog_text" msgid="5751657130671431216">"Жазу және трансляциялау кезінде <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ойнатылған аудиомазмұн, құпия сөздер, төлем мәліметтері, фотосуреттер және хабарлар сияқты кез келген құпия ақпаратты сақтай алады."</string>
+    <string name="media_projection_dialog_title" msgid="8124184308671641248">"Трансляциялау/жазу кезінде құпия ақпаратты көрсету"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Қайта көрсетпеу"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Барлығын тазалау"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Басқару"</string>
@@ -632,8 +634,8 @@
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"Хабарландырулар келе берсін"</string>
     <string name="inline_turn_off_notifications" msgid="8635596135532202355">"Хабарландыруларды өшіру"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"Осы қолданбаның хабарландырулары көрсетілсін бе?"</string>
-    <string name="hint_text_block" msgid="3554459167504485284">"Тыйым салынған хабарландырулар еш жерде көрсетілмейді немесе дыбыс шығармайды. Хабарландыруларды параметрлерден бөгей алмайсыз."</string>
-    <string name="hint_text_silent" msgid="859468056340177016">"Дыбыссыз хабарландырулар көлеңкеде шығады, бірақ құлыптау экранына шықпайды, баннерде ұсынылады және дыбысты ойнатады."</string>
+    <string name="hint_text_block" msgid="3554459167504485284">"Тыйым салынған хабарландырулар еш жерде көрсетілмейді немесе дыбыс шығармайды. Тыйымды алу үшін параметрлерге өтіңіз."</string>
+    <string name="hint_text_silent" msgid="859468056340177016">"Дыбыссыз хабарландырулар көлеңкеде шығады, бірақ құлып экранына шықпайды, баннерде ұсынылады және дыбысты ойнатады."</string>
     <string name="hint_text_alert" msgid="2721169810318722524">"Бұл дыбыстық хабарландырулар хабарландыру тартпасында, күй жолағында және құлып экранында көрсетіледі."</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"Хабарландыруларды өшіру мүмкін емес"</string>
     <string name="notification_multichannel_desc" msgid="4695920306092240550">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string>
@@ -717,7 +719,7 @@
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"Дыбыс деңгейін басқару элементтерімен бірге көрсету"</string>
     <string name="volume_and_do_not_disturb" msgid="1750270820297253561">"Мазаламау"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"Дыбыс деңгейі түймелерінің төте жолы"</string>
-    <string name="volume_up_silent" msgid="7545869833038212815">"Дыбысы арттырылған кезде, мазаламау режимінен шығу"</string>
+    <string name="volume_up_silent" msgid="7545869833038212815">"Дыбысы арттырылған кезде, \"Мазаламау\" режимінен шығу"</string>
     <string name="battery" msgid="7498329822413202973">"Батарея"</string>
     <string name="clock" msgid="7416090374234785905">"Сағат"</string>
     <string name="headset" msgid="4534219457597457353">"Құлақаспап жинағы"</string>
@@ -898,10 +900,10 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчиктер өшірулі"</string>
     <string name="device_services" msgid="1191212554435440592">"Құрылғы қызметтері"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Атауы жоқ"</string>
-    <string name="restart_button_description" msgid="2035077840254950187">"Бұл қолданбаны іске қосу үшін түртіп, толық экранға өтіңіз."</string>
+    <string name="restart_button_description" msgid="2035077840254950187">"Бұл қолданбаны қайта қосып, толық экранға өту үшін түртіңіз."</string>
     <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын ашу"</string>
     <string name="bubbles_settings_button_description" msgid="2970630476657287189">"<xliff:g id="APP_NAME">%1$s</xliff:g> қалқымалы анықтамаларының параметрлері"</string>
-    <string name="bubbles_prompt" msgid="8807968030159469710">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында қалқымалы анықтамаларға рұқсат етілсін бе?"</string>
+    <string name="bubbles_prompt" msgid="8807968030159469710">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының қалқымалы анықтамаларына рұқсат етілсін бе?"</string>
     <string name="no_bubbles" msgid="337101288173078247">"Тыйым салу"</string>
     <string name="yes_bubbles" msgid="668809525728633841">"Рұқсат беру"</string>
     <string name="ask_me_later_bubbles" msgid="2147688438402939029">"Кейінірек сұралсын"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 0d19e1f..11764e1 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 5a6a52c..04c7bd2 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -277,8 +279,7 @@
       <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ಕ್ಕಿಂತ ಹೆಚ್ಚು ಅಧಿಸೂಚನೆಗಳು ಒಳಗಿವೆ.</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> ಕ್ಕಿಂತ ಹೆಚ್ಚು ಅಧಿಸೂಚನೆಗಳು ಒಳಗಿವೆ.</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ಅಧಿಸೂಚನೆ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ಪರದೆಯು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಿರುಗುತ್ತದೆ."</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"ಈ ಸೂಚನೆಗಳು ನಿಮ್ಮನ್ನು ಎಚ್ಚರಿಸುತ್ತವೆ"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"ನೀವು ಸಾಮಾನ್ಯವಾಗಿ ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಿದ್ದೀರಿ. \nಅವುಗಳನ್ನು ತೋರಿಸುತ್ತಲೇ ಇರಬೇಕೆ?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"ಅನ್ವಯಿಸಿ"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸುತ್ತಲೇ ಇರಬೇಕೆ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಲ್ಲಿಸಿ"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"ಮೌನವಾಗಿ ವಿತರಿಸಿ"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"ನಿರ್ಬಂಧಿಸಿ"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"ತೋರಿಸುತ್ತಲಿರಿ"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"ಕಿರಿದುಗೊಳಿಸಿ"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"ಹಿತವಾಗಿ"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"ಮೌನವಾಗಿರಿ"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"ಅಡಚಣೆ"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"ಎಚ್ಚರಿಸುತ್ತಿರಿ"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"ಅಧಿಸೂಚನೆಗಳನ್ನು ಆಫ್ ಮಾಡಿ"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"ಈ ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸುತ್ತಲೇ ಇರಬೇಕೆ?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"ನಿರ್ಬಂಧಿಸಲಾದ ಅಧಿಸೂಚನೆಗಳು ಎಲ್ಲಿಯೂ ಗೋಚರಿಸುವುದಿಲ್ಲ ಅಥವಾ ಯಾವುದೇ ಧ್ವನಿಯನ್ನು ಪ್ಲೇ ಮಾಡುವುದಿಲ್ಲ. ನೀವು ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅಧಿಸೂಚನೆಗಳ ನಿರ್ಬಂಧವನ್ನು ರದ್ದುಗೊಳಿಸಬಹುದು."</string>
     <string name="hint_text_silent" msgid="859468056340177016">"ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳು ಶೇಡ್‌ನಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ, ಆದರೆ ಲಾಕ್ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಗೋಚರಿಸುವುದಿಲ್ಲ, ಬ್ಯಾನರ್ ಪ್ರಸ್ತುತಪಡಿಸುತ್ತವೆ ಅಥವಾ ಧ್ವನಿಯನ್ನು ಪ್ಲೇ ಮಾಡುತ್ತವೆ."</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ವೀಕರಿಸಿದಾಗ ಧ್ವನಿಯನ್ನು ಮಾಡುತ್ತವೆ ಮತ್ತು ಅಧಿಸೂಚನೆ ಡ್ರಾಯರ್, ಸ್ಥಿತಿ ಪಟ್ಟಿ ಮತ್ತು ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತದೆ"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆಫ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"ಈ ಗುಂಪಿನ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇಲ್ಲಿ ಕಾನ್ಫಿಗರ್‌ ಮಾಡಲಾಗಿರುವುದಿಲ್ಲ"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಮೂಲಕ"</string>
     <string name="appops_camera" msgid="8100147441602585776">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸುತ್ತಿದೆ."</string>
     <string name="appops_microphone" msgid="741508267659494555">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ಬಳಸುತ್ತಿದೆ."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d7bf351..56a6af2 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G 이상"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 937c146..75308a5 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 8046632..b2103c8 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index e8500c1..28fa2c6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 1b6db06..77ff3b0 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-mcc310-mnc030/config.xml b/packages/SystemUI/res/values-mcc310-mnc030/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc030/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc070/config.xml b/packages/SystemUI/res/values-mcc310-mnc070/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc070/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc170/config.xml b/packages/SystemUI/res/values-mcc310-mnc170/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc170/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc280/config.xml b/packages/SystemUI/res/values-mcc310-mnc280/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc280/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc380/config.xml b/packages/SystemUI/res/values-mcc310-mnc380/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc380/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc410/config.xml b/packages/SystemUI/res/values-mcc310-mnc410/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc410/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc560/config.xml b/packages/SystemUI/res/values-mcc310-mnc560/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc560/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc950/config.xml b/packages/SystemUI/res/values-mcc310-mnc950/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc950/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc311-mnc180/config.xml b/packages/SystemUI/res/values-mcc311-mnc180/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc311-mnc180/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 6ac95b9..985fa7b6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -704,7 +705,7 @@
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
     <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Известувања"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Кратенки на тастатурата"</string>
-    <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Промени распоред на тастатура"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Промени јазик на тастатура"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апликации"</string>
     <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помош"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Прелистувач"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 1f71904..25b4720 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -63,10 +63,8 @@
     <string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"ഉപകരണത്തിൽ ഇപ്പോൾ സൈൻ ഇൻ ചെയ്‌തിരിക്കുന്ന ഉപയോക്താവിന് USB ഡീബഗ്ഗിംഗ് ഓണാക്കാനാകില്ല. ഈ ഫീച്ചർ ഉപയോഗിക്കാൻ പ്രാഥമിക ഉപയോക്താവിലേക്ക് മാറുക."</string>
     <string name="usb_contaminant_title" msgid="206854874263058490">"USB പോർട്ട് പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="usb_contaminant_message" msgid="2205845572186473860">"ദ്രാവകത്തിൽ നിന്നോ പൊടിയിൽ നിന്നോ നിങ്ങളുടെ ഉപകരണത്തെ പരിരക്ഷിക്കാനായി USB പോർട്ട് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നതിനാൽ അത് ആക്‌സസറികളൊന്നും തിരിച്ചറിയില്ല.\n\n USB പോർട്ട് സുരക്ഷിതമായി വീണ്ടും ഉപയോഗിക്കാനാകുമ്പോൾ നിങ്ങളെ അറിയിക്കും."</string>
-    <!-- no translation found for usb_port_enabled (7906141351687694867) -->
-    <skip />
-    <!-- no translation found for usb_disable_contaminant_detection (2103905315747120033) -->
-    <skip />
+    <string name="usb_port_enabled" msgid="7906141351687694867">"ആക്‌സസറികളും ചാർജറുകളും കണ്ടെത്താൻ USB പോർട്ട് പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="usb_disable_contaminant_detection" msgid="2103905315747120033">"USB പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ സൂം ചെയ്യുക"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ വലിച്ചുനീട്ടുക"</string>
     <string name="global_action_screenshot" msgid="8329831278085426283">"സ്‌ക്രീൻഷോട്ട്"</string>
@@ -113,8 +111,7 @@
     <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കാതെ അൺലോക്കുചെയ്യുക"</string>
     <string name="accessibility_scanning_face" msgid="769545173211758586">"മുഖം സ്കാൻ ചെയ്യുന്നു"</string>
     <string name="accessibility_send_smart_reply" msgid="7766727839703044493">"അയയ്ക്കുക"</string>
-    <!-- no translation found for accessibility_manage_notification (2026361503393549753) -->
-    <skip />
+    <string name="accessibility_manage_notification" msgid="2026361503393549753">"അറിയിപ്പുകൾ മാനേജ് ചെയ്യുക"</string>
     <string name="unlock_label" msgid="8779712358041029439">"അൺലോക്കുചെയ്യുക"</string>
     <string name="phone_label" msgid="2320074140205331708">"ഫോൺ തുറക്കുക"</string>
     <string name="voice_assist_label" msgid="3956854378310019854">"വോയ്‌സ് അസിസ്റ്റ് തുറക്കുക"</string>
@@ -175,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -185,8 +184,7 @@
     <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>
-    <!-- no translation found for not_default_data_content_description (9194667237765917844) -->
-    <skip />
+    <string name="not_default_data_content_description" msgid="9194667237765917844">"ഡാറ്റ ഉപയോഗിക്കുന്നതിന് സജ്ജീകരിച്ചിട്ടില്ല"</string>
     <string name="cell_data_off" msgid="1051264981229902873">"ഓഫ്"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ബ്ലൂടൂത്ത് ടെതറിംഗ്."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"ഫ്ലൈറ്റ് മോഡ്."</string>
@@ -228,12 +226,9 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ഫ്ലൈറ്റ് മോഡ് ഓണാക്കി."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="2960643943620637020">"പൂർണ്ണ നിശബ്‌ദത"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"അലാറങ്ങൾ മാത്രം"</string>
-    <!-- no translation found for accessibility_quick_settings_dnd (5555155552520665891) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_dnd_changed_off (2757071272328547807) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_dnd_changed_on (6808220653747701059) -->
-    <skip />
+    <string name="accessibility_quick_settings_dnd" msgid="5555155552520665891">"ശല്യപ്പെടുത്തരുത്."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="2757071272328547807">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓഫാക്കി."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="6808220653747701059">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓണാക്കി."</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ബ്ലൂടൂത്ത് ഓഫാണ്."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ബ്ലൂടൂത്ത് ഓണാണ്."</string>
@@ -284,8 +279,7 @@
       <item quantity="other">ഉള്ളിൽ <xliff:g id="NUMBER_1">%s</xliff:g> അറിയിപ്പുകൾ കൂടിയുണ്ട്.</item>
       <item quantity="one">ഉള്ളിൽ <xliff:g id="NUMBER_0">%s</xliff:g> അറിയിപ്പ് കൂടിയുണ്ട്.</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"അറിയിപ്പ് ക്രമീകരണങ്ങൾ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ക്രമീകരണം"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"സ്‌ക്രീൻ സ്വയമേവ തിരിയും."</string>
@@ -298,8 +292,7 @@
     <string name="start_dreams" msgid="5640361424498338327">"സ്ക്രീൻ സേവർ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ഇതർനെറ്റ്"</string>
     <string name="quick_settings_header_onboarding_text" msgid="8030309023792936283">"കൂടുതൽ ഓപ്ഷനുകൾക്കായി ഐക്കണുകൾ സ്‌പർശിച്ച് പിടിക്കുക"</string>
-    <!-- no translation found for quick_settings_dnd_label (7112342227663678739) -->
-    <skip />
+    <string name="quick_settings_dnd_label" msgid="7112342227663678739">"ശല്യപ്പെടുത്തരുത്"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"മുൻഗണന മാത്രം"</string>
     <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"അലാറങ്ങൾ മാത്രം"</string>
     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"പൂർണ്ണ നിശബ്‌ദത"</string>
@@ -450,10 +443,8 @@
     <string name="battery_saver_notification_title" msgid="8614079794522291840">"ബാറ്ററി ലാഭിക്കൽ ഓണാണ്"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്‌ക്കുന്നു"</string>
     <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുക"</string>
-    <!-- no translation found for media_projection_dialog_text (5751657130671431216) -->
-    <skip />
-    <!-- no translation found for media_projection_dialog_title (8124184308671641248) -->
-    <skip />
+    <string name="media_projection_dialog_text" msgid="5751657130671431216">"റിക്കോർഡ് ചെയ്യുമ്പോഴോ കാസ്‌റ്റ് ചെയ്യുമ്പോഴോ, നിങ്ങൾ പ്ലേ ചെയ്യുന്ന ഓഡിയോയും പാസ്‌വേഡുകളും, പേയ്മെന്റ് വിവരം, ഫോട്ടോകൾ, സന്ദേശങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ന് ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
+    <string name="media_projection_dialog_title" msgid="8124184308671641248">"കാസ്‌റ്റ് /റിക്കോർഡ് ചെയ്യുമ്പോൾ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരം വെളിപ്പെടുത്തുന്നു"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"വീണ്ടും കാണിക്കരുത്"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"എല്ലാം മായ്‌ക്കുക"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"മാനേജ് ചെയ്യുക"</string>
@@ -528,10 +519,8 @@
     <string name="accessibility_volume_settings" msgid="4915364006817819212">"ശബ്‌ദ ക്രമീകരണം"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"വികസിപ്പിക്കുക"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ചുരുക്കുക"</string>
-    <!-- no translation found for volume_odi_captions_tip (1193653197906918269) -->
-    <skip />
-    <!-- no translation found for accessibility_volume_close_odi_captions_tip (1163987066404128967) -->
-    <skip />
+    <string name="volume_odi_captions_tip" msgid="1193653197906918269">"മീഡിയയ്ക്ക് സ്വയമേവ ക്യാപ്ഷൻ"</string>
+    <string name="accessibility_volume_close_odi_captions_tip" msgid="1163987066404128967">"അടിക്കുറിപ്പുകൾക്കുള്ള നുറുങ്ങ്"</string>
     <string name="accessibility_output_chooser" msgid="8185317493017988680">"ഔട്ട്‌പുട്ട് ഉപകരണം മാറുക"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"സ്‌ക്രീൻ പിൻ ചെയ്‌തു"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ\', \'ചുരുക്കവിവരണം\' എന്നിവ സ്‌പർശിച്ച് പിടിക്കുക."</string>
@@ -632,32 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"ഈ അറിയിപ്പുകൾ നിങ്ങൾക്ക് മുന്നറിയിപ്പ് നൽകും"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"സാധാരണയായി നിങ്ങൾ ഈ അറിയിപ്പുകൾ നിരാകരിക്കുന്നു. \nഅവ തുടർന്നും കാണിക്കണോ?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"പൂർത്തിയായി"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"ബാധകമാക്കുക"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ഈ അറിയിപ്പുകൾ തുടർന്നും കാണിക്കണോ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"അറിയിപ്പുകൾ നിർത്തുക"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"നിശബ്‌ദമായി ഡെലിവർ ചെയ്യുക"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"ബ്ലോക്ക് ചെയ്യുക"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"തുടർന്നും കാണിക്കുക"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"ചെറുതാക്കുക‍"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"നിശബ്‌ദമായ"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"നിശബ്‌ദമായ നിലയിൽ തുടരുക"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"തടസ്സപ്പെടുത്തുന്ന"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"മുന്നറിയിപ്പ് നൽകുന്നത് തുടരുക"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"അറിയിപ്പുകൾ ഓഫാക്കുക"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"ഈ ആപ്പിൽ നിന്നുള്ള അറിയിപ്പുകൾ തുടർന്നും കാണിക്കണോ?"</string>
-    <!-- no translation found for hint_text_block (3554459167504485284) -->
-    <skip />
-    <!-- no translation found for hint_text_silent (859468056340177016) -->
-    <skip />
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_block" msgid="3554459167504485284">"ബ്ലോക്ക് ചെയ്‌ത അറിയിപ്പുകൾ എവിടെയും ദൃശ്യമാവുകയോ ശബ്‌ദം പ്ലേ ചെയ്യുകയോ ഇല്ല. ക്രമീകരണത്തിൽ നിങ്ങൾക്ക് അറിയിപ്പുകൾ അൺബ്ലോക്ക് ചെയ്യാനാവും."</string>
+    <string name="hint_text_silent" msgid="859468056340177016">"നിശബ്‌ദ അറിയിപ്പുകൾ ഷെയ്‌ഡിൽ ദൃശ്യമാകും, പക്ഷെ ലോക്ക് സ്‌ക്രീനിൽ ദൃശ്യമാവുകയോ ബാനർ അവതരിപ്പിക്കുകയോ ഒരു ശബ്‌ദം പ്ലേ ചെയ്യുകയോ ഇല്ല."</string>
+    <string name="hint_text_alert" msgid="2721169810318722524">"ഈ അറിയിപ്പുകൾ ഒരു ശബ്‌ദമുണ്ടാക്കുകയും അറിയിപ്പ് ഡ്രോയർ, സ്‌റ്റാറ്റസ് ബാർ, ലോക്ക് സ്ക്രീൻ എന്നിവയിൽ കാണിക്കുകയും ചെയ്യും"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"ഈ അറിയിപ്പുകൾ ഓഫാക്കാനാവില്ല"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്‍ഫിഗര്‍ ചെയ്യാൻ കഴിയില്ല"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> വഴി"</string>
     <string name="appops_camera" msgid="8100147441602585776">"ഈ ആപ്പ് ക്യാമറ ഉപയോഗിക്കുന്നുണ്ട്."</string>
     <string name="appops_microphone" msgid="741508267659494555">"ഈ ആപ്പ് മൈക്രോഫോൺ ഉപയോഗിക്കുന്നു."</string>
@@ -736,11 +717,9 @@
     <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
     <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"കലണ്ടർ"</string>
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"വോളിയം നിയന്ത്രണങ്ങളോടൊപ്പം കാണിക്കുക"</string>
-    <!-- no translation found for volume_and_do_not_disturb (1750270820297253561) -->
-    <skip />
+    <string name="volume_and_do_not_disturb" msgid="1750270820297253561">"ശല്യപ്പെടുത്തരുത്"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"വോളിയം ബട്ടൺ കുറുക്കുവഴി"</string>
-    <!-- no translation found for volume_up_silent (7545869833038212815) -->
-    <skip />
+    <string name="volume_up_silent" msgid="7545869833038212815">"ശബ്‌ദം കൂടുമ്പോൾ \'ശല്യപ്പെടുത്തരുതിൽ\' നിന്ന് പുറത്ത് കടക്കൂ"</string>
     <string name="battery" msgid="7498329822413202973">"ബാറ്ററി"</string>
     <string name="clock" msgid="7416090374234785905">"ക്ലോക്ക്"</string>
     <string name="headset" msgid="4534219457597457353">"ഹെഡ്‌സെറ്റ്"</string>
@@ -881,8 +860,7 @@
     <string name="go_to_web" msgid="2650669128861626071">"ബ്രൗസറിലേക്ക് പോവുക"</string>
     <string name="mobile_data" msgid="7094582042819250762">"മൊബൈൽ ഡാറ്റ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
-    <!-- no translation found for mobile_carrier_text_format (3241721038678469804) -->
-    <skip />
+    <string name="mobile_carrier_text_format" msgid="3241721038678469804">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"വൈഫൈ ഓഫാണ്"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"Bluetooth ഓഫാണ്"</string>
     <string name="dnd_is_off" msgid="6167780215212497572">"\'ശല്യപ്പെടുത്തരുത്\' ഓഫാണ്"</string>
@@ -922,30 +900,18 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"സെൻസറുകൾ ഓഫാണ്"</string>
     <string name="device_services" msgid="1191212554435440592">"ഉപകരണ സേവനങ്ങള്‍"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"പേരില്ല"</string>
-    <!-- no translation found for restart_button_description (2035077840254950187) -->
-    <skip />
+    <string name="restart_button_description" msgid="2035077840254950187">"ഈ ആപ്പ് റീസ്‌റ്റാർട്ട് ചെയ്യാനും പൂർണ്ണ സ്‌ക്രീനാവാനും ടാപ്പ് ചെയ്യുക."</string>
     <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> തുറക്കുക"</string>
-    <!-- no translation found for bubbles_settings_button_description (2970630476657287189) -->
-    <skip />
-    <!-- no translation found for bubbles_prompt (8807968030159469710) -->
-    <skip />
-    <!-- no translation found for no_bubbles (337101288173078247) -->
-    <skip />
+    <string name="bubbles_settings_button_description" msgid="2970630476657287189">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനുള്ള ബബിളുകളുടെ ക്രമീകരണം"</string>
+    <string name="bubbles_prompt" msgid="8807968030159469710">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ൽ നിന്നും ബബിളുകളെ അനുവദിക്കണോ?"</string>
+    <string name="no_bubbles" msgid="337101288173078247">"നിരസിക്കുക"</string>
     <string name="yes_bubbles" msgid="668809525728633841">"അനുവദിക്കുക"</string>
-    <!-- no translation found for ask_me_later_bubbles (2147688438402939029) -->
-    <skip />
-    <!-- no translation found for bubble_content_description_single (1184462974339387516) -->
-    <skip />
-    <!-- no translation found for bubble_content_description_stack (8666349184095622232) -->
-    <skip />
-    <!-- no translation found for bubble_accessibility_action_move (1794879742234803840) -->
-    <skip />
-    <!-- no translation found for bubble_accessibility_action_move_top_left (104736832249802724) -->
-    <skip />
-    <!-- no translation found for bubble_accessibility_action_move_top_right (1671844272347036806) -->
-    <skip />
-    <!-- no translation found for bubble_accessibility_action_move_bottom_left (206369104473183217) -->
-    <skip />
-    <!-- no translation found for bubble_accessibility_action_move_bottom_right (8705660152384312329) -->
-    <skip />
+    <string name="ask_me_later_bubbles" msgid="2147688438402939029">"എന്നോട് പിന്നീട് ചോദിക്കുക"</string>
+    <string name="bubble_content_description_single" msgid="1184462974339387516">"<xliff:g id="APP_NAME">%2$s</xliff:g>-ൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+    <string name="bubble_content_description_stack" msgid="8666349184095622232">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> കൂടുതലും"</string>
+    <string name="bubble_accessibility_action_move" msgid="1794879742234803840">"നീക്കുക"</string>
+    <string name="bubble_accessibility_action_move_top_left" msgid="104736832249802724">"മുകളിൽ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
+    <string name="bubble_accessibility_action_move_top_right" msgid="1671844272347036806">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
+    <string name="bubble_accessibility_action_move_bottom_left" msgid="206369104473183217">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
+    <string name="bubble_accessibility_action_move_bottom_right" msgid="8705660152384312329">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index dcb5c2d..e414ea9 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index e84e03a..a913a00 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"४G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"१X"</string>
@@ -277,8 +279,7 @@
       <item quantity="one">आत आणखी <xliff:g id="NUMBER_1">%s</xliff:g> सूचना.</item>
       <item quantity="other">आत आणखी <xliff:g id="NUMBER_1">%s</xliff:g> सूचना.</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"सूचना सेटिंग्ज"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिंग्ज"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रीन स्वयंचलितपणे फिरेल."</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"या सूचना तुम्हाला इशारा देतील"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"तुम्ही या सूचना सामान्यतः डिसमिस करता. \nते दाखवत राहायचे?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"पूर्ण झाले"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"लागू करा"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"या सूचना दाखवणे सुरू ठेवायचे?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"सूचना थांबवा"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"शांतपणे पाठवा"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"ब्लॉक करा"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"दाखवणे सुरू ठेवा"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"लहान करा"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"नाजूक"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"सायलंट रहा"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"व्यत्यय आणणारे"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"सूचना देत रहा"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"सूचना बंद करा"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"या अ‍ॅपकडील सूचना दाखवणे सुरू ठेवायचे?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"ब्लॉक केलेल्या सूचना कुठेही दिसत नाहीत किंवा आवाज प्ले करत नाहीत. तुम्ही सेटिंग्जमध्ये सूचना अनब्लॉक करू शकता."</string>
     <string name="hint_text_silent" msgid="859468056340177016">"सायलंट सूचना रंगछटेमध्ये दिसतात, परंतु लॉक स्क्रीनवर दिसत नाहीत, बॅनर दाखवत नाहीत किंवा आवाज प्ले करत नाहीत."</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"या सूचना आवाज करतील आणि सूचना ड्राॅवर, स्टेटस बार आणि लॉक स्क्रीनवर दाखवल्या जातील"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"या सूचना बंद करता येत नाहीत"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"या सूचनांचा संच येथे कॉन्फिगर केला जाऊ शकत नाही"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> मार्गे"</string>
     <string name="appops_camera" msgid="8100147441602585776">"हे अ‍ॅप कॅमेरा वापरत आहे."</string>
     <string name="appops_microphone" msgid="741508267659494555">"हे अ‍ॅप मायक्रोफोन वापरत आहे."</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index dc3d832..76472b6 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 40b21cc..ac9b531 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 75a5730..c35c3ec 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index ebe76ec..98e1a96 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -277,8 +279,7 @@
       <item quantity="other">भित्र थप <xliff:g id="NUMBER_1">%s</xliff:g> सूचनाहरू छन्।</item>
       <item quantity="one">भित्र थप <xliff:g id="NUMBER_0">%s</xliff:g> सूचना छ।</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"अधिसूचना सेटिङहरू"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिङहरू"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रिन स्वतः घुम्ने छ।"</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"यी सूचनाहरूले तपाईंलाई सतर्क गरिने छ"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"तपाईं सामान्यतया यी सूचनाहरूलाई खारेज गर्ने गर्नुहुन्छ। \nतिनलाई देखाइरहने हो?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"सम्पन्न भयो"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"लागू गर्नुहोस्"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"यी सूचनाहरू देखाउने क्रम जारी राख्ने हो?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"सूचनाहरू देखाउन छाड्नुहोस्"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"मौन रूपमा डेलिभर गर्नुहोस्"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"रोक लगाउनुहोस्"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"देखाउने क्रम जारी राख्नुहोस्"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"सानो बनाउनुहोस्"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"हलुका"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"मौन रहनुहोस्"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"बाधा पुर्याइरहने"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"सर्तक गराइरहनुहोस्"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"सूचनाहरू निष्क्रिय पार्नुहोस्"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"यो अनुप्रयोगका सूचनाहरू देखाउने क्रम जारी राख्ने हो?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"रोक लगाइएका सूचनाहरू कतै पनि देखिँदैनन् वा कुनै आवाज गर्दैनन्। तपाईं सेटिङहरूमा सूचनाहरूमाथिको रोक हटाउन सक्नुहुन्छ।"</string>
     <string name="hint_text_silent" msgid="859468056340177016">"मौन सूचनाहरू ओझेलमा देखिन्छन् तर स्क्रिन लक हुँदा देखिँदैनन्, ब्यानर देखाउँदैनन् अनि कुनै आवाज पनि दिँदैनन्।"</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"यी सूचनाहरू आउँदा ध्वनि बज्ने छ र तिनीहरू सूचनाको ड्रअर, स्थिति पट्टी र लक स्क्रिनमा देखिने छन्"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"यी सूचनाहरूलाई निष्क्रिय पार्न सकिँदैन"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"यहाँबाट सूचनाहरूको यो समूह कन्फिगर गर्न सकिँदैन"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> मार्फत"</string>
     <string name="appops_camera" msgid="8100147441602585776">"यो अनुप्रयोगले क्यामेराको प्रयोग गर्दै छ।"</string>
     <string name="appops_microphone" msgid="741508267659494555">"यो अनुप्रयोगले माइक्रोफोनको प्रयोग गर्दै छ।"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index bad9821..d963138 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
     <string name="battery_low_title" msgid="9187898087363540349">"Batterij is bijna leeg"</string>
-    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend"</string>
-    <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> resterend, nog ongeveer <xliff:g id="TIME">%2$s</xliff:g> over op basis van je gebruik"</string>
-    <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> resterend, nog ongeveer <xliff:g id="TIME">%2$s</xliff:g> over"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend. Batterijbesparing is ingeschakeld."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Nog <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Nog <xliff:g id="PERCENTAGE">%1$s</xliff:g>, dat is ongeveer <xliff:g id="TIME">%2$s</xliff:g> op basis van je gebruik"</string>
+    <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Nog <xliff:g id="PERCENTAGE">%1$s</xliff:g>, dat is ongeveer <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Nog <xliff:g id="PERCENTAGE">%s</xliff:g>. Batterijbesparing is ingeschakeld."</string>
     <string name="invalid_charger" msgid="2741987096648693172">"Kan niet opladen via USB. Gebruik de oplader die bij je apparaat is geleverd."</string>
     <string name="invalid_charger_title" msgid="2836102177577255404">"Kan niet opladen via USB"</string>
     <string name="invalid_charger_text" msgid="6480624964117840005">"Gebruik de oplader die bij je apparaat is geleverd"</string>
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -795,7 +796,7 @@
     <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-melding: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"App werkt mogelijk niet met gesplitst scherm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App biedt geen ondersteuning voor gesplitst scherm."</string>
-    <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"App werkt mogelijk niet op een secundair display."</string>
+    <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"App werkt mogelijk niet op een secundair scherm."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"App kan niet op secundaire displays worden gestart."</string>
     <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Instellingen openen."</string>
     <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Snelle instellingen openen."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 4c68841..65ac6c0 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index d8d5429..6a5c11d 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -225,7 +227,7 @@
     <string name="accessibility_quick_settings_dnd_none_on" msgid="2960643943620637020">"ਸੰਪੂਰਨ ਖਾਮੋਸ਼ੀ"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"ਸਿਰਫ਼ ਅਲਾਰਮ"</string>
     <string name="accessibility_quick_settings_dnd" msgid="5555155552520665891">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ।"</string>
-    <string name="accessibility_quick_settings_dnd_changed_off" msgid="2757071272328547807">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਬੰਦ ਕਰੋ।"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="2757071272328547807">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="6808220653747701059">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"ਬਲੂਟੁੱਥ।"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth ਬੰਦ।"</string>
@@ -277,8 +279,7 @@
       <item quantity="one">ਅੰਦਰ <xliff:g id="NUMBER_1">%s</xliff:g> ਹੋਰ ਸੂਚਨਾਵਾਂ।</item>
       <item quantity="other">ਅੰਦਰ <xliff:g id="NUMBER_1">%s</xliff:g> ਹੋਰ ਸੂਚਨਾਵਾਂ।</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ਸੂਚਨਾ ਸੈਟਿੰਗਾਂ"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ਸੈਟਿੰਗਾਂ"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ਸਕ੍ਰੀਨ ਆਟੋਮੈਟਿਕਲੀ ਰੋਟੇਟ ਕਰੇਗੀ।"</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"ਇਹ ਸੂਚਨਾਵਾਂ ਤੁਹਾਨੂੰ ਸੁਚੇਤ ਕਰਨਗੀਆਂ"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਆਮ ਤੌਰ \'ਤੇ ਖਾਰਜ ਕਰਦੇ ਹੋ। \nਕੀ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"ਹੋ ਗਿਆ"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"ਲਾਗੂ ਕਰੋ"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ਕੀ ਇਨ੍ਹਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"ਸੂਚਨਾਵਾਂ ਬੰਦ ਕਰੋ"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"ਚੁੱਪ-ਚਪੀਤੇ ਡਿਲੀਵਰ ਕਰੋ"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"ਬਲਾਕ ਕਰੋ"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖੋ"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"ਛੋਟਾ ਕਰੋ"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"ਅਰਾਮਦੇਹ"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"ਚੁੱਪ ਰਹੋ"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"ਰੁਕਾਵਟੀ"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"ਸੁਚੇਤ ਰਖੋ"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"ਸੂਚਨਾਵਾਂ ਬੰਦ ਕਰੋ"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"ਕੀ ਇਸ ਐਪ ਤੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"ਬਲਾਕ ਕੀਤੀਆਂ ਸੂਚਨਾਵਾਂ ਕਿਤੇ ਵੀ ਨਹੀਂ ਦਿਸਦੀਆਂ ਜਾਂ ਕੋਈ ਧੁਨੀ ਨਹੀਂ ਵਜਾਉਂਦੀਆਂ। ਤੁਸੀਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸੂਚਨਾਵਾਂ ਨੂੰ ਅਣਬਲਾਕ ਕਰ ਸਕਦੇ ਹੋ।"</string>
-    <string name="hint_text_silent" msgid="859468056340177016">"ਚੁੱਪ ਸੂਚਨਾਵਾਂ ਭਾਹ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ ਪਰ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ, ਬੈਨਰ ਦੇ ਰੂਪ ਵਿੱਚ ਨਹੀਂ ਦਿਸਦੀਆਂ ਹਨ ਅਤੇ ਇੱਕ ਧੁਨੀ ਵਜਾਉਂਦੀਆਂ ਹਨ।"</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_silent" msgid="859468056340177016">"ਚੁੱਪ ਸੂਚਨਾਵਾਂ ਭਾਹ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ ਪਰ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ, ਬੈਨਰ ਦੇ ਰੂਪ ਵਿੱਚ ਨਹੀਂ ਦਿਸਦੀਆਂ ਹਨ, ਜਾਂ ਕੋਈ ਧੁਨੀ ਵਜਾਉਂਦੀਆਂ ਹਨ।"</string>
+    <string name="hint_text_alert" msgid="2721169810318722524">"ਇਹ ਸੂਚਨਾਵਾਂ ਅਵਾਜ਼ ਕਰਨਗੀਆਂ ਅਤੇ ਸੂਚਨਾ ਦਰਾਜ਼, ਸਥਿਤੀ ਪੱਟੀ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਿਸਣਗੀਆਂ"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"ਇਨ੍ਹਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬੰਦ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"ਇਹ ਸੂਚਨਾਵਾਂ ਦਾ ਗਰੁੱਪ ਇੱਥੇ ਸੰਰੂਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਰਾਹੀਂ"</string>
     <string name="appops_camera" msgid="8100147441602585776">"ਇਹ ਐਪ ਕੈਮਰੇ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀ ਹੈ।"</string>
     <string name="appops_microphone" msgid="741508267659494555">"ਇਹ ਐਪ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀ ਹੈ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index af4acd3..c42faae 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -172,6 +172,9 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -678,7 +681,7 @@
       <item quantity="other">%d minuty</item>
       <item quantity="one">]%d minuta</item>
     </plurals>
-    <string name="battery_panel_title" msgid="7944156115535366613">"Wykorzystanie baterii"</string>
+    <string name="battery_panel_title" msgid="7944156115535366613">"Zużycie baterii"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Oszczędzanie baterii nie jest dostępne podczas ładowania"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Oszczędzanie baterii"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Zmniejsza wydajność i ogranicza dane w tle"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8b7449f..1d3cf8d 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -34,7 +34,7 @@
     <string name="invalid_charger_text" msgid="6480624964117840005">"Usar o carregador que acompanha o dispositivo"</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Configurações"</string>
     <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Ativar Economia de bateria?"</string>
-    <string name="battery_saver_confirmation_title_generic" msgid="2090922638411744540">"Sobre a \"Economia de bateria\""</string>
+    <string name="battery_saver_confirmation_title_generic" msgid="2090922638411744540">"Sobre a Economia de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ativar"</string>
     <string name="battery_saver_start_action" msgid="8187820911065797519">"Ativar a Economia de bateria"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -880,11 +881,11 @@
     <string name="slice_permission_checkbox" msgid="7986504458640562900">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
     <string name="slice_permission_allow" msgid="2340244901366722709">"Permitir"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Negar"</string>
-    <string name="auto_saver_title" msgid="1217959994732964228">"Toque para programar o recurso \"Economia de bateria\""</string>
+    <string name="auto_saver_title" msgid="1217959994732964228">"Toque para programar o recurso Economia de bateria"</string>
     <string name="auto_saver_text" msgid="6324376061044218113">"Ativar automaticamente quando a bateria estiver em <xliff:g id="PERCENTAGE">%d</xliff:g>%%"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Não"</string>
-    <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Programação do recurso \"Economia de bateria\" ativada"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"O recurso \"Economia de bateria\" será ativado automaticamente depois que a bateria ficar abaixo de <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
+    <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Programação do recurso Economia de bateria ativada"</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"O recurso Economia de bateria será ativado automaticamente depois que a bateria ficar abaixo de <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Configurações"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"Ok"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Despejar pilha SysUI"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 104eb45..e58de4f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8b7449f..1d3cf8d 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -34,7 +34,7 @@
     <string name="invalid_charger_text" msgid="6480624964117840005">"Usar o carregador que acompanha o dispositivo"</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Configurações"</string>
     <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Ativar Economia de bateria?"</string>
-    <string name="battery_saver_confirmation_title_generic" msgid="2090922638411744540">"Sobre a \"Economia de bateria\""</string>
+    <string name="battery_saver_confirmation_title_generic" msgid="2090922638411744540">"Sobre a Economia de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Ativar"</string>
     <string name="battery_saver_start_action" msgid="8187820911065797519">"Ativar a Economia de bateria"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -880,11 +881,11 @@
     <string name="slice_permission_checkbox" msgid="7986504458640562900">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
     <string name="slice_permission_allow" msgid="2340244901366722709">"Permitir"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Negar"</string>
-    <string name="auto_saver_title" msgid="1217959994732964228">"Toque para programar o recurso \"Economia de bateria\""</string>
+    <string name="auto_saver_title" msgid="1217959994732964228">"Toque para programar o recurso Economia de bateria"</string>
     <string name="auto_saver_text" msgid="6324376061044218113">"Ativar automaticamente quando a bateria estiver em <xliff:g id="PERCENTAGE">%d</xliff:g>%%"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Não"</string>
-    <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Programação do recurso \"Economia de bateria\" ativada"</string>
-    <string name="auto_saver_enabled_text" msgid="874711029884777579">"O recurso \"Economia de bateria\" será ativado automaticamente depois que a bateria ficar abaixo de <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
+    <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Programação do recurso Economia de bateria ativada"</string>
+    <string name="auto_saver_enabled_text" msgid="874711029884777579">"O recurso Economia de bateria será ativado automaticamente depois que a bateria ficar abaixo de <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Configurações"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"Ok"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"Despejar pilha SysUI"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ee30926..2837aa7 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7ee314d..1236224 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index a75f3d2..bba9e79 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 535a868..f38889b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -678,7 +680,7 @@
       <item quantity="other">%d minút</item>
       <item quantity="one">%d minúta</item>
     </plurals>
-    <string name="battery_panel_title" msgid="7944156115535366613">"Využitie batérie"</string>
+    <string name="battery_panel_title" msgid="7944156115535366613">"Spotreba batérie"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Počas nabíjania nie je Šetrič batérie k dispozícii"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Šetrič batérie"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Obmedzí výkonnosť a údaje na pozadí"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 11b262a..f8c3c99 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -714,7 +715,7 @@
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazaj"</string>
     <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obvestila"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Bližnjične tipke"</string>
-    <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Preklop razporeda tipkovnice"</string>
+    <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Preklop postavitve tipkovnice"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
     <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoč"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brskalnik"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 5b728a6..6cc23e2 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -497,12 +499,12 @@
     <string name="monitoring_description_ca_cert_settings_separator" msgid="4987350385906393626">" "</string>
     <string name="monitoring_description_ca_cert_settings" msgid="5489969458872997092">"Hap kredencialet e besuara"</string>
     <string name="monitoring_description_network_logging" msgid="7223505523384076027">"Administratori yt ka aktivizuar regjistrimin e rrjetit, i cili monitoron trafikun në pajisjen tënde.\n\nPër më shumë informacione, kontakto me administratorin."</string>
-    <string name="monitoring_description_vpn" msgid="4445150119515393526">"I dhe leje një aplikacioni që të konfigurojë një lidhje VPN.\n\nKy aplikacion mund të monitorojë pajisjen tënde dhe aktivitetin e rrjetit, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
+    <string name="monitoring_description_vpn" msgid="4445150119515393526">"I dhe leje një aplikacioni që të konfigurojë një lidhje VPN.\n\nKy aplikacion mund të monitorojë pajisjen tënde dhe aktivitetin e rrjetit, përfshirë email-et, aplikacionet dhe sajtet e uebit."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë aktivitetin tënd të rrjetit, duke përfshirë email-et, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacion, kontakto me administratorin tënd.\n\nJe i lidhur edhe me një VPN, që mund të monitorojë aktivitetin tënd të rrjetit."</string>
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="1828472472674709532">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g> i cili mund të monitorojë aktivitetin tënd në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit."</string>
-    <string name="monitoring_description_app_personal" msgid="484599052118316268">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
-    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
+    <string name="monitoring_description_app_personal" msgid="484599052118316268">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë email-et, aplikacionet dhe sajtet e uebit."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë email-et, aplikacionet dhe sajtet e uebit."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profili është i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacione, kontakto me administratorin."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profili është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
     <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Shkyçur për <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c3e1c94..8b1a695 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -376,7 +377,7 @@
     <string name="recents_quick_scrub_onboarding" msgid="2778062804333285789">"Превуците удесно да бисте брзо променили апликације"</string>
     <string name="quick_step_accessibility_toggle_overview" msgid="7171470775439860480">"Укључи/искључи преглед"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
-    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Пуњење"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Пуни се"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до краја пуњења"</string>
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не пуни се"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 380acc8..b335402 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index f359ac0..494dfc9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-sw372dp/dimens.xml b/packages/SystemUI/res/values-sw372dp/dimens.xml
index 717f18f..e64662e 100644
--- a/packages/SystemUI/res/values-sw372dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw372dp/dimens.xml
@@ -17,6 +17,5 @@
 -->
 <resources>
     <dimen name="nav_content_padding">8dp</dimen>
-    <dimen name="rounded_corner_content_padding">8dp</dimen>
     <dimen name="qs_header_tile_margin_horizontal">13dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index edfb20d..c9b9dca 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -176,6 +176,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -285,8 +287,7 @@
       <item quantity="other">உள்ளே மேலும் <xliff:g id="NUMBER_1">%s</xliff:g> அறிவிப்புகள் உள்ளன.</item>
       <item quantity="one">உள்ளே மேலும் <xliff:g id="NUMBER_0">%s</xliff:g> அறிவிப்பு உள்ளது.</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"அறிவிப்பு அமைப்புகள்"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> அமைப்புகள்"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"திரை தானாகச் சுழலும்."</string>
@@ -633,32 +634,26 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"இந்த அறிவிப்புகள் விழிப்பூட்டலாக அமையும்"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"வழக்கமாக, இந்த அறிவிப்புகளை நிராகரிக்கிறீர்கள். \nதொடர்ந்து இவற்றைக் காட்டலாமா?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"முடிந்தது"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"பயன்படுத்து"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"இந்த அறிவிப்புகளைத் தொடர்ந்து காட்டவா?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"அறிவிப்புகளை நிறுத்து"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"ஒலியின்றி அறிவிப்புகளை வழங்கு"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"தடு"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"அறிவிப்புகளைத் தொடர்ந்து காட்டு"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"சிறிதாக்கு"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"ஜென்டில்"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"அறிவிப்புகளை ஒலியின்றிக் காட்டு"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"இண்ட்டரப்டிவ்"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"தொடர்ந்து விழிப்பூட்டு"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"அறிவிப்புகளை முடக்கு"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"இந்தப் பயன்பாட்டின் அறிவிப்புகளைத் தொடர்ந்து காட்டவா?"</string>
     <!-- no translation found for hint_text_block (3554459167504485284) -->
     <skip />
     <!-- no translation found for hint_text_silent (859468056340177016) -->
     <skip />
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"அறிவிப்பு டிராயரிலும், நிலைப் பட்டியிலும், பூட்டுத் திரையிலும் ஒலியுடன் அறிவிக்கப்படும்"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"இந்த அறிவிப்புகளை ஆஃப் செய்ய முடியாது"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> மூலமாக"</string>
     <string name="appops_camera" msgid="8100147441602585776">"இந்த ஆப்ஸானது கேமராவை உபயோகிக்கிறது."</string>
     <string name="appops_microphone" msgid="741508267659494555">"இந்த ஆப்ஸானது, மைக்ரோஃபோனை உபயோகிக்கிறது."</string>
@@ -727,7 +722,7 @@
     <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"அறிவிப்புகள்"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"கீபோர்ட் ஷார்ட்கட்கள்"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"கீபோர்டு லே அவுட்டை மாற்று"</string>
-    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"பயன்பாடுகள்"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ஆப்ஸ்"</string>
     <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"அசிஸ்ட்"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"உலாவி"</string>
     <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"தொடர்புகள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index ab56204..d87f11b 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -41,7 +41,7 @@
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"స్క్రీన్ ఆటో-రొటేట్‌"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"మ్యూట్"</string>
-    <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"స్వయంచాలకం"</string>
+    <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ఆటోమేటిక్"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"నోటిఫికేషన్‌లు"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"బ్లూటూత్ టీథర్ చేయబడింది"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ఇన్‌పుట్ పద్ధతులను సెటప్ చేయండి"</string>
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -225,7 +227,7 @@
     <string name="accessibility_quick_settings_dnd_none_on" msgid="2960643943620637020">"మొత్తం నిశ్శబ్దం"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"అలారాలు మాత్రమే"</string>
     <string name="accessibility_quick_settings_dnd" msgid="5555155552520665891">"అంతరాయం కలిగించవద్దు."</string>
-    <string name="accessibility_quick_settings_dnd_changed_off" msgid="2757071272328547807">"అంతరాయం కలిగించవద్దు ఆఫ్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="2757071272328547807">"\'అంతరాయం కలిగించవద్దు\' ఆఫ్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="6808220653747701059">"అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"బ్లూటూత్."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"బ్లూటూత్ ఆఫ్‌లో ఉంది."</string>
@@ -277,8 +279,7 @@
       <item quantity="other">లోపల మరో <xliff:g id="NUMBER_1">%s</xliff:g> నోటిఫికేషన్‌లు ఉన్నాయి.</item>
       <item quantity="one">లోపల మరో <xliff:g id="NUMBER_0">%s</xliff:g> నోటిఫికేషన్ ఉంది.</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"నోటిఫికేషన్ సెట్టింగ్‌లు"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> సెట్టింగ్‌లు"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"స్క్రీన్ స్వయంచాలకంగా తిప్పబడుతుంది."</string>
@@ -337,7 +338,7 @@
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"పరికరాలు ఏవీ అందుబాటులో లేవు"</string>
     <string name="quick_settings_cast_no_wifi" msgid="2696477881905521882">"Wi‑Fi కనెక్ట్ కాలేదు"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ప్రకాశం"</string>
-    <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"స్వయంచాలకం"</string>
+    <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ఆటోమేటిక్"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"రంగులను తారుమారు చేయి"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"రంగు సవరణ మోడ్"</string>
     <string name="quick_settings_more_settings" msgid="326112621462813682">"మరిన్ని సెట్టింగ్‌లు"</string>
@@ -518,7 +519,7 @@
     <string name="accessibility_volume_settings" msgid="4915364006817819212">"ధ్వని సెట్టింగ్‌లు"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"విస్తరింపజేయండి"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"కుదించండి"</string>
-    <string name="volume_odi_captions_tip" msgid="1193653197906918269">"ఆటోమేటిక్ క్యాప్షన్ మీడియా"</string>
+    <string name="volume_odi_captions_tip" msgid="1193653197906918269">"మీడియాకు ఆటోమేటిక్ శీర్షికలు"</string>
     <string name="accessibility_volume_close_odi_captions_tip" msgid="1163987066404128967">"ఉపశీర్షికల చిట్కాను మూసివేయండి"</string>
     <string name="accessibility_output_chooser" msgid="8185317493017988680">"పరికరం అవుట్‌పుట్‌ని మార్చండి"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"స్క్రీన్ పిన్ చేయబడింది"</string>
@@ -620,30 +621,24 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"ఈ నోటిఫికేషన్‌లు మిమ్మల్ని హెచ్చరిస్తాయి"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"మీరు సాధారణంగా ఈ నోటిఫికేషన్‌లను విస్మరిస్తారు. \nవాటి ప్రదర్శనను కొనసాగించాలా?"</string>
     <string name="inline_done_button" msgid="492513001558716452">"పూర్తయింది"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"వర్తింపజేయి"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ఈ నోటిఫికేషన్‌లను చూపిస్తూ ఉండాలా?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"నోటిఫికేషన్‌లను ఆపివేయి"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"నిశ్శబ్దంగా బట్వాడా చేయండి"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"బ్లాక్ చేయి"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"చూపిస్తూనే ఉండు"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"కుదించు"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"సున్నితం"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"నిశబ్దంగా తెలియజేయి"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"అంతరాయం"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"ఎప్పటికప్పుడు హెచ్చరించు"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"నోటిఫికేషన్‌లను ఆఫ్ చేయి"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"ఈ యాప్ నుండి నోటిఫికేషన్‌లను చూపిస్తూ ఉండాలా?"</string>
     <string name="hint_text_block" msgid="3554459167504485284">"బ్లాక్ చేసిన నోటిఫికే‌షన్‌లు ఎక్కడా కనిపించవు, అలాగే శబ్దం ప్లే కాదు. మీరు సెట్టింగ్‌లలో నోటిఫికేషన్‌లను అన్‌బ్లాక్ చేయవచ్చు."</string>
     <string name="hint_text_silent" msgid="859468056340177016">"నిశ్శబ్ద నోటిఫికేషన్‌లు షేడ్‌లో కనిపిస్తాయి, కానీ లాక్ స్క్రీన్‌పై కనిపించవు, బ్యానర్‌లుగా అందించబడవు, అలాగే సౌండ్ ప్లే కాదు."</string>
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"ఈ నోటిఫికేషన్‌లు శబ్దాన్ని చేస్తూ నోటిఫికేషన్ డ్రాయర్, స్థితి పట్టీ మరియు లాక్ స్క్రీన్‌లో చూపుతాయి"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"ఈ నోటిఫికేషన్‌లను ఆఫ్ చేయలేరు"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"ఈ నోటిఫికేషన్‌ల సమూహాన్ని ఇక్కడ కాన్ఫిగర్ చేయలేము"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"<xliff:g id="APP_NAME">%1$s</xliff:g> ద్వారా"</string>
     <string name="appops_camera" msgid="8100147441602585776">"ఈ యాప్ ఈ కెమెరాను ఉపయోగిస్తోంది."</string>
     <string name="appops_microphone" msgid="741508267659494555">"ఈ యాప్ మైక్రోఫోన్‌ను ఉపయోగిస్తుంది."</string>
@@ -724,7 +719,7 @@
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"వాల్యూమ్ నియంత్రణలతో చూపు"</string>
     <string name="volume_and_do_not_disturb" msgid="1750270820297253561">"అంతరాయం కలిగించవద్దు"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"వాల్యూమ్ బటన్‌ల షార్ట్‌కట్"</string>
-    <string name="volume_up_silent" msgid="7545869833038212815">"వాల్యూమ్ పెంచితే అంతరాయం కలిగించవద్దు నుండి నిష్క్రమిస్తుంది"</string>
+    <string name="volume_up_silent" msgid="7545869833038212815">"వాల్యూమ్ పెంచితే \'అంతరాయం కలిగించవద్దు\' ను ఆపివేస్తుంది"</string>
     <string name="battery" msgid="7498329822413202973">"బ్యాటరీ"</string>
     <string name="clock" msgid="7416090374234785905">"గడియారం"</string>
     <string name="headset" msgid="4534219457597457353">"హెడ్‌సెట్"</string>
@@ -911,7 +906,7 @@
     <string name="bubbles_prompt" msgid="8807968030159469710">"<xliff:g id="APP_NAME">%1$s</xliff:g> నుండి బబుల్‌లను అనుమతించాలా?"</string>
     <string name="no_bubbles" msgid="337101288173078247">"తిరస్కరించు"</string>
     <string name="yes_bubbles" msgid="668809525728633841">"అనుమతించు"</string>
-    <string name="ask_me_later_bubbles" msgid="2147688438402939029">"నన్ను తర్వాత అడగండి"</string>
+    <string name="ask_me_later_bubbles" msgid="2147688438402939029">"నన్ను తర్వాత అడగు"</string>
     <string name="bubble_content_description_single" msgid="1184462974339387516">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_content_description_stack" msgid="8666349184095622232">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> మరియు మరో <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
     <string name="bubble_accessibility_action_move" msgid="1794879742234803840">"తరలించు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0068ea6..98d45a1 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -706,7 +707,7 @@
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"แป้นพิมพ์ลัด"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"สลับรูปแบบแป้นพิมพ์"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"แอปพลิเคชัน"</string>
-    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"การสนับสนุน"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ผู้ช่วย"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"เบราว์เซอร์"</string>
     <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"รายชื่อติดต่อ"</string>
     <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"อีเมล"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 4b843a3..5c5180c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 793ac72..3e39588 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -172,6 +172,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 110d76e..5b66836 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index b4372d9..5205250 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -175,6 +175,8 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+‎"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+‎"</string>
+    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
+    <skip />
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+‎"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X‎"</string>
@@ -284,8 +286,7 @@
       <item quantity="other">اندر <xliff:g id="NUMBER_1">%s</xliff:g> مزید اطلاعات ہیں۔ </item>
       <item quantity="one">اندر <xliff:g id="NUMBER_0">%s</xliff:g> مزید اطلاع ہے۔</item>
     </plurals>
-    <!-- no translation found for notification_summary_message_format (715071952312553396) -->
-    <skip />
+    <string name="notification_summary_message_format" msgid="715071952312553396">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"اطلاع کی ترتیبات"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ترتیبات"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"اسکرین خود بخود گردش کرے گی۔"</string>
@@ -632,32 +633,26 @@
     <string name="notification_channel_unsilenced" msgid="4790904571552394137">"یہ اطلاعات آپ کو الرٹ کریں گی"</string>
     <string name="inline_blocking_helper" msgid="3055064577771478591">"آپ عام طور پر ان اطلاعات کو مسترد کرتے ہیں۔ \nان کو دکھاتے رہیں؟"</string>
     <string name="inline_done_button" msgid="492513001558716452">"ہو گیا"</string>
-    <!-- no translation found for inline_ok_button (975600017662930615) -->
-    <skip />
+    <string name="inline_ok_button" msgid="975600017662930615">"لاگو کریں"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"یہ اطلاعات دکھانا جاری رکھیں؟"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"اطلاعات روک دیں"</string>
     <string name="inline_deliver_silently_button" msgid="7756289895745629140">"خاموشی سے ڈیلیور کریں"</string>
     <string name="inline_block_button" msgid="8735843688021655065">"مسدود کریں"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"دکھانا جاری رکھیں"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"چھوٹا کریں"</string>
-    <!-- no translation found for inline_silent_button_silent (6904727667411781466) -->
-    <skip />
+    <string name="inline_silent_button_silent" msgid="6904727667411781466">"لطیف"</string>
     <string name="inline_silent_button_stay_silent" msgid="6308371431217601009">"خاموش رہیں"</string>
-    <!-- no translation found for inline_silent_button_alert (2449191160203602471) -->
-    <skip />
+    <string name="inline_silent_button_alert" msgid="2449191160203602471">"خلل انداز"</string>
     <string name="inline_silent_button_keep_alerting" msgid="327696842264359693">"متنبہ کرنا جاری رکھیں"</string>
-    <!-- no translation found for inline_turn_off_notifications (8635596135532202355) -->
-    <skip />
+    <string name="inline_turn_off_notifications" msgid="8635596135532202355">"اطلاعات کو آف کریں"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"اس ایپ کی طرف سے اطلاعات دکھانا جاری رکھیں؟"</string>
     <!-- no translation found for hint_text_block (3554459167504485284) -->
     <skip />
     <!-- no translation found for hint_text_silent (859468056340177016) -->
     <skip />
-    <!-- no translation found for hint_text_alert (2721169810318722524) -->
-    <skip />
+    <string name="hint_text_alert" msgid="2721169810318722524">"یہ اطلاعات آواز پیدا کریں گی اور اطلاعاتی دراز، اسٹیٹس بار میں اور مقفل اسکرین پر ظاہر ہوں گی"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"ان اطلاعات کو آف نہیں کیا جا سکتا"</string>
-    <!-- no translation found for notification_multichannel_desc (4695920306092240550) -->
-    <skip />
+    <string name="notification_multichannel_desc" msgid="4695920306092240550">"اطلاعات کے اس گروپ کو یہاں کنفیگر نہیں کیا جا سکتا"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"بذریعہ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="appops_camera" msgid="8100147441602585776">"یہ ایپ کیمرے کا استعمال کر رہی ہے۔"</string>
     <string name="appops_microphone" msgid="741508267659494555">"یہ ایپ مائیکروفون کا استعمال کر رہی ہے۔"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 292f4ef..5225305 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -160,7 +160,7 @@
     <string name="accessibility_three_bars" msgid="2648241415119396648">"Uchta ustun."</string>
     <string name="accessibility_signal_full" msgid="9122922886519676839">"Signal to‘liq."</string>
     <string name="accessibility_desc_on" msgid="2385254693624345265">"Yoniq"</string>
-    <string name="accessibility_desc_off" msgid="6475508157786853157">"O‘chiq"</string>
+    <string name="accessibility_desc_off" msgid="6475508157786853157">"Yoqilmagan"</string>
     <string name="accessibility_desc_connected" msgid="8366256693719499665">"Ulangan."</string>
     <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Ulanmoqda…"</string>
     <string name="data_connection_gprs" msgid="7652872568358508452">"GPRS"</string>
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -189,7 +190,7 @@
     <string name="accessibility_vpn_on" msgid="5993385083262856059">"VPN yoniq."</string>
     <string name="accessibility_no_sims" msgid="3957997018324995781">"SIM karta yo‘q."</string>
     <string name="carrier_network_change_mode" msgid="8149202439957837762">"Mobil tarmoqni o‘zgartirish"</string>
-    <string name="accessibility_battery_details" msgid="7645516654955025422">"Batareya quvvati sarfi haqida ma’lumot"</string>
+    <string name="accessibility_battery_details" msgid="7645516654955025422">"Quvvat sarfi tafsilotlari"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batareya <xliff:g id="NUMBER">%d</xliff:g> foiz."</string>
     <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batareya quvvat olmoqda (<xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%)."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Tizim sozlamalari."</string>
@@ -604,13 +605,13 @@
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Yoqish"</string>
-    <string name="show_silently" msgid="6841966539811264192">"Bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Tovushsiz chiqsin"</string>
     <string name="block" msgid="2734508760962682611">"Barcha bildirishnomalar bloklansin"</string>
     <string name="do_not_silence" msgid="6878060322594892441">"Ovozi o‘chirilmasin"</string>
     <string name="do_not_silence_block" msgid="4070647971382232311">"Ovozi o‘chirilmasin yoki bloklanmasin"</string>
     <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Bildirishnomalar uchun kengaytirilgan boshqaruv"</string>
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Yoniq"</string>
-    <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"O‘chiq"</string>
+    <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Yoqilmagan"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Bildirishnomalar uchun kengaytirilgan boshqaruv yordamida ilova bildirishnomalarining muhimlik darajasini (0-5) sozlash mumkin. \n\n"<b>"5-daraja"</b>" \n- Bildirishnomani ro‘yxatning boshida ko‘rsatish \n- To‘liq ekranli bildirishnomalarni ko‘rsatish \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"4-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"3-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n\n"<b>"2-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n\n"<b>"1-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n- Ekran qulfi va holat qatorida ko‘rsatmaslik \n- Bildirishnomani ro‘yxatning oxirida ko‘rsatish \n\n"<b>"0-daraja"</b>" \n- Ilovadan keladigan barcha bildirishnomalarni bloklash"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirishnomalar"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Bu bildirishnomalar endi chiqmaydi"</string>
@@ -728,7 +729,7 @@
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Trafik tejash yoniq"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Trafik tejash o‘chiq"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Yoniq"</string>
-    <string name="switch_bar_off" msgid="8803270596930432874">"O‘chiq"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Yoqilmagan"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Navigatsiya paneli"</string>
     <string name="nav_bar_layout" msgid="3664072994198772020">"Sxema"</string>
     <string name="left_nav_bar_button_type" msgid="8555981238887546528">"Qo‘shimcha Chapga tugmasi turi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 5db2324..7c95e4e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G trở lên"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
@@ -362,7 +363,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Giới hạn <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="7608026833638817218">"Hồ sơ công việc"</string>
-    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Chế độ ánh sáng ban đêm"</string>
+    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ánh sáng đêm"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Bật khi trời tối"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Cho đến khi trời sáng"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"Bật vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ea35df9..8f014d2 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 0245e56..cdbea3d 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 01b5c7a..e0a4a50 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1f465cc..c587f31 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -172,6 +172,7 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"I-LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"I-LTE+"</string>
+    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
     <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
     <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml
index 41e0786..ced26c9 100644
--- a/packages/SystemUI/res/values/attrs_car.xml
+++ b/packages/SystemUI/res/values/attrs_car.xml
@@ -15,16 +15,23 @@
 -->
 
 <resources>
+    <attr name="icon" format="reference"/>
+    <attr name="selectedIcon" format="reference"/>
+    <attr name="intent" format="string"/>
+    <attr name="longIntent" format="string"/>
+    <attr name="selectedAlpha" format="float" />
+    <attr name="unselectedAlpha" format="float" />
+
     <!-- Allow for custom attribs to be added to a facet button -->
     <declare-styleable name="CarFacetButton">
         <!-- icon to be rendered (drawable) -->
-        <attr name="icon" format="reference"/>
+        <attr name="icon"/>
         <!-- icon to be rendered when in selected state -->
-        <attr name="selectedIcon" format="reference"/>
+        <attr name="selectedIcon"/>
         <!-- intent to start when button is click -->
-        <attr name="intent" format="string"/>
+        <attr name="intent"/>
         <!-- intent to start when a long press has happened -->
-        <attr name="longIntent" format="string"/>
+        <attr name="longIntent"/>
         <!-- categories that will be added as extras to the fired intents -->
         <attr name="categories" format="string"/>
         <!-- package names that will be added as extras to the fired intents -->
@@ -32,9 +39,9 @@
         <!-- componentName names that will be used for detecting selected state -->
         <attr name="componentNames" format="string" />
         <!-- Alpha value to used when in selected state.  Defaults 1f  -->
-        <attr name="selectedAlpha" format="float" />
+        <attr name="selectedAlpha" />
         <!-- Alpha value to used when in un-selected state.  Defaults 0.7f  -->
-        <attr name="unselectedAlpha" format="float" />
+        <attr name="unselectedAlpha" />
         <!-- Render a "more" icon. Defaults true  -->
         <attr name="useMoreIcon" format="boolean" />
 
@@ -44,17 +51,17 @@
     <!-- Allow for custom attribs to be added to a nav button -->
     <declare-styleable name="CarNavigationButton">
         <!-- intent to start when button is click -->
-        <attr name="intent" format="string"/>
+        <attr name="intent" />
         <!-- intent to start when a long press has happened -->
-        <attr name="longIntent" format="string"/>
+        <attr name="longIntent" />
         <!-- start the intent as a broad cast instead of an activity if true-->
         <attr name="broadcast" format="boolean"/>
         <!-- Alpha value to used when in selected state.  Defaults 1f  -->
-        <attr name="selectedAlpha" format="float" />
+        <attr name="selectedAlpha" />
         <!-- Alpha value to used when in un-selected state.  Defaults 0.7f  -->
-        <attr name="unselectedAlpha" format="float" />
+        <attr name="unselectedAlpha" />
         <!-- icon to be rendered when in selected state -->
-        <attr name="selectedIcon" format="reference"/>
+        <attr name="selectedIcon" />
     </declare-styleable>
 
     <!-- Custom attributes to configure hvac values -->
@@ -89,6 +96,6 @@
         </attr>
 
         <!-- Icon resource ids to render on UI -->
-        <attr name="icon" format="reference"/>
+        <attr name="icon" />
     </declare-styleable>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ce04638..e02be38 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -114,7 +114,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night
+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,dark,saver,work,cast,night
     </string>
 
     <!-- The tiles to display in QuickSettings -->
@@ -316,6 +316,7 @@
         <item>com.android.systemui.SliceBroadcastRelayHandler</item>
         <item>com.android.systemui.SizeCompatModeActivityController</item>
         <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
+        <item>com.android.systemui.theme.ThemeOverlayController</item>
     </string-array>
 
     <!-- SystemUI vender service, used in config_systemUIServiceComponents. -->
@@ -486,4 +487,7 @@
 
     <integer name="ongoing_appops_dialog_max_apps">5</integer>
 
+    <!-- Launcher package name for overlaying icons. -->
+    <string name="launcher_overlayable_package" translatable="false">com.android.launcher3</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6dfe701..74924fb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -238,6 +238,9 @@
     <!-- the padding on the end of the statusbar -->
     <dimen name="status_bar_padding_end">8dp</dimen>
 
+    <!-- the padding on the top of the statusbar (usually 0) -->
+    <dimen name="status_bar_padding_top">0dp</dimen>
+
     <!-- the radius of the overflow dot in the status bar -->
     <dimen name="overflow_dot_radius">2dp</dimen>
 
diff --git a/packages/SystemUI/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml
index 930cfce..c29a51f 100644
--- a/packages/SystemUI/res/values/internal.xml
+++ b/packages/SystemUI/res/values/internal.xml
@@ -17,6 +17,7 @@
 <resources>
     <dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen>
     <dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
+    <dimen name="navigation_bar_frame_height">@*android:dimen/navigation_bar_frame_height</dimen>
     <dimen name="navigation_bar_height_car_mode">@*android:dimen/navigation_bar_height_car_mode</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f47d4b5..444cabfc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -424,6 +424,9 @@
     <!-- Content description of the data connection type LTE+. [CHAR LIMIT=NONE] -->
     <string name="data_connection_lte_plus">LTE+</string>
 
+    <!-- Content description of the data connection type 5Ge. [CHAR LIMIT=NONE] -->
+    <string name="data_connection_5ge" translate="false">5Ge</string>
+
     <!-- Content description of the data connection type 5G. [CHAR LIMIT=NONE] -->
     <string name="data_connection_5g" translate="false">5G</string>
 
@@ -865,6 +868,8 @@
     <string name="quick_settings_night_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
     <!-- QuickSettings: Secondary text for when the Night Light or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
     <string name="quick_settings_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
+    <!-- QuickSettings: Label for the toggle to activate Dark theme (A.K.A Dark Mode). [CHAR LIMIT=20] -->
+    <string name="quick_settings_ui_mode_night_label">Dark Theme</string>
 
     <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
     <string name="quick_settings_nfc_label">NFC</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 04701bc..577e3bb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -124,9 +124,14 @@
      */
     void onAssistantVisibilityChanged(float visibility) = 14;
 
-    /*
+    /**
      * Sent when back is triggered.
      */
     void onBackAction(boolean completed, int downX, int downY, boolean isButton,
             boolean gestureSwipeLeft) = 15;
+
+    /**
+     * Sent when some system ui state changes.
+     */
+    void onSystemUiStateChanged(int stateFlags) = 16;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 1413ac1..98a8110 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -23,7 +23,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
 
 /**
  * Data for a single thumbnail.
@@ -53,9 +52,7 @@
     }
 
     public ThumbnailData(TaskSnapshot snapshot) {
-        thumbnail = Bitmap.wrapHardwareBuffer(
-                HardwareBuffer.createFromGraphicBuffer(snapshot.getSnapshot()),
-                snapshot.getColorSpace());
+        thumbnail = Bitmap.wrapHardwareBuffer(snapshot.getSnapshot(), snapshot.getColorSpace());
         insets = new Rect(snapshot.getContentInsets());
         orientation = snapshot.getOrientation();
         reducedResolution = snapshot.isReducedResolution();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 1076e73..b36a88b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -20,12 +20,16 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.Resources;
 import android.view.WindowManagerPolicyConstants;
 
 import com.android.internal.policy.ScreenDecorationsUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Various shared constants between Launcher and SysUI as part of quickstep
  */
@@ -44,6 +48,17 @@
     public static final String NAV_BAR_MODE_GESTURAL_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
+    public static final int SYSUI_STATE_SCREEN_PINNING = 1 << 0;
+    public static final int SYSUI_STATE_NAV_BAR_HIDDEN = 1 << 1;
+    public static final int SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED = 1 << 2;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SYSUI_STATE_SCREEN_PINNING,
+            SYSUI_STATE_NAV_BAR_HIDDEN,
+            SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+    })
+    public @interface SystemUiStateFlags {}
+
     /**
      * Touch slopes and thresholds for quick step operations. Drag slop is the point where the
      * home button press/long press over are ignored and will start to drag when exceeded and the
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 1d9105c..d2fe5cd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -77,9 +77,15 @@
         }
     }
 
-    public void finish(boolean toHome) {
+    /**
+     * Finish the current recents animation.
+     * @param toHome Going to home or back to the previous app.
+     * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous
+     *                          app.
+     */
+    public void finish(boolean toHome, boolean sendUserLeaveHint) {
         try {
-            mAnimationController.finish(toHome);
+            mAnimationController.finish(toHome, sendUserLeaveHint);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to finish recents animation", e);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index b738b57..70366a8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -138,6 +138,7 @@
             ClockManager clockManager) {
         super(context, attrs);
         mStatusBarStateController = statusBarStateController;
+        mStatusBarState = mStatusBarStateController.getState();
         mSysuiColorExtractor = colorExtractor;
         mClockManager = clockManager;
         mTransition = new ClockBoundsTransition();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 59ee267..7ffee5d 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -37,7 +37,6 @@
      */
     private View mDigitalClock;
     private View mAnalogClock;
-    private View mTypeClock;
 
     /**
      * Pixel shifting amplitidues used to prevent screen burn-in.
@@ -62,7 +61,6 @@
         super.onFinishInflate();
         mDigitalClock = findViewById(R.id.digital_clock);
         mAnalogClock = findViewById(R.id.analog_clock);
-        mTypeClock = findViewById(R.id.type_clock);
 
         // Get pixel shifting X, Y amplitudes from resources.
         Resources resources = getResources();
@@ -95,11 +93,5 @@
             mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
                     + offsetY);
         }
-
-        // Put the typographic clock part way down the screen.
-        if (mTypeClock != null) {
-            mTypeClock.setX(offsetX);
-            mTypeClock.setY(0.2f * getHeight() + offsetY);
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 64e56f9..e373ca1 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -20,8 +20,10 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
@@ -35,6 +37,7 @@
 import com.android.systemui.dock.DockManager.DockEventListener;
 import com.android.systemui.plugins.ClockPlugin;
 import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.InjectionInflationController;
 
@@ -61,6 +64,7 @@
     private final ContentResolver mContentResolver;
     private final SettingsWrapper mSettingsWrapper;
     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private final CurrentUserTracker mCurrentUserTracker;
 
     /**
      * Observe settings changes to know when to switch the clock face.
@@ -68,9 +72,11 @@
     private final ContentObserver mContentObserver =
             new ContentObserver(mMainHandler) {
                 @Override
-                public void onChange(boolean selfChange) {
-                    super.onChange(selfChange);
-                    reload();
+                public void onChange(boolean selfChange, Uri uri, int userId) {
+                    super.onChange(selfChange, uri, userId);
+                    if (userId == mCurrentUserTracker.getCurrentUserId()) {
+                        reload();
+                    }
                 }
             };
 
@@ -123,6 +129,12 @@
         mPluginManager = pluginManager;
         mContentResolver = contentResolver;
         mSettingsWrapper = settingsWrapper;
+        mCurrentUserTracker = new CurrentUserTracker(context) {
+            @Override
+            public void onUserSwitched(int newUserId) {
+                reload();
+            }
+        };
         mPreviewClocks = new AvailableClocks();
 
         Resources res = context.getResources();
@@ -132,7 +144,6 @@
         addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
         addBuiltinClock(() -> new StretchAnalogClockController(res, layoutInflater,
                 colorExtractor));
-        addBuiltinClock(() -> new TypeClockController(res, layoutInflater, colorExtractor));
 
         // Store the size of the display for generation of clock preview.
         DisplayMetrics dm = res.getDisplayMetrics();
@@ -203,10 +214,11 @@
         mPluginManager.addPluginListener(mPreviewClocks, ClockPlugin.class, true);
         mContentResolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
-                false, mContentObserver);
+                false, mContentObserver, UserHandle.USER_ALL);
         mContentResolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.DOCKED_CLOCK_FACE),
-                false, mContentObserver);
+                false, mContentObserver, UserHandle.USER_ALL);
+        mCurrentUserTracker.startTracking();
         if (mDockManager == null) {
             mDockManager = SysUiServiceProvider.getComponent(mContext, DockManager.class);
         }
@@ -218,6 +230,7 @@
     private void unregister() {
         mPluginManager.removePluginListener(mPreviewClocks);
         mContentResolver.unregisterContentObserver(mContentObserver);
+        mCurrentUserTracker.stopTracking();
         if (mDockManager != null) {
             mDockManager.removeListener(mDockEventListener);
         }
@@ -334,7 +347,8 @@
         private ClockPlugin getClockPlugin() {
             ClockPlugin plugin = null;
             if (ClockManager.this.isDocked()) {
-                final String name = mSettingsWrapper.getDockedClockFace();
+                final String name = mSettingsWrapper.getDockedClockFace(
+                        mCurrentUserTracker.getCurrentUserId());
                 if (name != null) {
                     plugin = mClocks.get(name);
                     if (plugin != null) {
@@ -342,7 +356,8 @@
                     }
                 }
             }
-            final String name = mSettingsWrapper.getLockScreenCustomClockFace();
+            final String name = mSettingsWrapper.getLockScreenCustomClockFace(
+                    mCurrentUserTracker.getCurrentUserId());
             if (name != null) {
                 plugin = mClocks.get(name);
             }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
index 58e1155..e1c658be 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
@@ -34,15 +34,19 @@
 
     /**
      * Gets the value stored in settings for the custom clock face.
+     *
+     * @param userId ID of the user.
      */
-    public String getLockScreenCustomClockFace() {
-        return Settings.Secure.getString(mContentResolver, CUSTOM_CLOCK_FACE);
+    public String getLockScreenCustomClockFace(int userId) {
+        return Settings.Secure.getStringForUser(mContentResolver, CUSTOM_CLOCK_FACE, userId);
     }
 
     /**
      * Gets the value stored in settings for the clock face to use when docked.
+     *
+     * @param userId ID of the user.
      */
-    public String getDockedClockFace() {
-        return Settings.Secure.getString(mContentResolver, DOCKED_CLOCK_FACE);
+    public String getDockedClockFace(int userId) {
+        return Settings.Secure.getStringForUser(mContentResolver, DOCKED_CLOCK_FACE, userId);
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
deleted file mode 100644
index 1c6b38b..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard.clock;
-
-import android.app.WallpaperManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.Paint.Style;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.keyguard.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.plugins.ClockPlugin;
-
-import java.util.TimeZone;
-
-/**
- * Plugin for a custom Typographic clock face that displays the time in words.
- */
-public class TypeClockController implements ClockPlugin {
-
-    /**
-     * Resources used to get title and thumbnail.
-     */
-    private final Resources mResources;
-
-    /**
-     * LayoutInflater used to inflate custom clock views.
-     */
-    private final LayoutInflater mLayoutInflater;
-
-    /**
-     * Extracts accent color from wallpaper.
-     */
-    private final SysuiColorExtractor mColorExtractor;
-
-    /**
-     * Renders preview from clock view.
-     */
-    private final ViewPreviewer mRenderer = new ViewPreviewer();
-
-    /**
-     * Custom clock shown on AOD screen and behind stack scroller on lock.
-     */
-    private View mView;
-    private TypographicClock mTypeClock;
-
-    /**
-     * Small clock shown on lock screen above stack scroller.
-     */
-    private TypographicClock mLockClock;
-
-    /**
-     * Controller for transition into dark state.
-     */
-    private CrossFadeDarkController mDarkController;
-
-    /**
-     * Create a TypeClockController instance.
-     *
-     * @param res Resources contains title and thumbnail.
-     * @param inflater Inflater used to inflate custom clock views.
-     * @param colorExtractor Extracts accent color from wallpaper.
-     */
-    TypeClockController(Resources res, LayoutInflater inflater,
-            SysuiColorExtractor colorExtractor) {
-        mResources = res;
-        mLayoutInflater = inflater;
-        mColorExtractor = colorExtractor;
-    }
-
-    private void createViews() {
-        mView = mLayoutInflater.inflate(R.layout.type_aod_clock, null);
-        mTypeClock = mView.findViewById(R.id.type_clock);
-
-        // For now, this view is used to hide the default digital clock.
-        // Need better transition to lock screen.
-        mLockClock = (TypographicClock) mLayoutInflater.inflate(R.layout.typographic_clock, null);
-        mLockClock.setVisibility(View.GONE);
-
-        mDarkController = new CrossFadeDarkController(mView, mLockClock);
-    }
-
-    @Override
-    public void onDestroyView() {
-        mView = null;
-        mTypeClock = null;
-        mLockClock = null;
-        mDarkController = null;
-    }
-
-    @Override
-    public String getName() {
-        return "type";
-    }
-
-    @Override
-    public String getTitle() {
-        return mResources.getString(R.string.clock_title_type);
-    }
-
-    @Override
-    public Bitmap getThumbnail() {
-        return BitmapFactory.decodeResource(mResources, R.drawable.type_thumbnail);
-    }
-
-    @Override
-    public Bitmap getPreview(int width, int height) {
-
-        // Use the big clock view for the preview
-        View view = getBigClockView();
-
-        // Initialize state of plugin before generating preview.
-        setDarkAmount(1f);
-        setTextColor(Color.WHITE);
-        ColorExtractor.GradientColors colors = mColorExtractor.getColors(
-                WallpaperManager.FLAG_LOCK, true);
-        setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
-        onTimeTick();
-
-        return mRenderer.createPreview(view, width, height);
-    }
-
-    @Override
-    public View getView() {
-        if (mLockClock == null) {
-            createViews();
-        }
-        return mLockClock;
-    }
-
-    @Override
-    public View getBigClockView() {
-        if (mView == null) {
-            createViews();
-        }
-        return mView;
-    }
-
-    @Override
-    public void setStyle(Style style) {}
-
-    @Override
-    public void setTextColor(int color) {
-        mTypeClock.setTextColor(color);
-        mLockClock.setTextColor(color);
-    }
-
-    @Override
-    public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
-        if (colorPalette == null || colorPalette.length == 0) {
-            return;
-        }
-        final int color = colorPalette[Math.max(0, colorPalette.length - 5)];
-        mTypeClock.setClockColor(color);
-        mLockClock.setClockColor(color);
-    }
-
-    @Override
-    public void onTimeTick() {
-        mTypeClock.onTimeChanged();
-        mLockClock.onTimeChanged();
-    }
-
-    @Override
-    public void setDarkAmount(float darkAmount) {
-        if (mDarkController != null) {
-            mDarkController.setDarkAmount(darkAmount);
-        }
-    }
-
-    @Override
-    public void onTimeZoneChanged(TimeZone timeZone) {
-        mTypeClock.onTimeZoneChanged(timeZone);
-        mLockClock.onTimeZoneChanged(timeZone);
-    }
-
-    @Override
-    public boolean shouldShowStatusArea() {
-        return false;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
deleted file mode 100644
index 572ab30..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard.clock;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.Annotation;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.SpannedString;
-import android.text.TextUtils;
-import android.text.format.DateFormat;
-import android.text.style.ForegroundColorSpan;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.keyguard.R;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * Clock that presents the time in words.
- */
-public class TypographicClock extends TextView {
-
-    private static final String ANNOTATION_COLOR = "color";
-
-    private final Resources mResources;
-    private final String[] mHours;
-    private final String[] mMinutes;
-    private int mAccentColor;
-    private final Calendar mTime = Calendar.getInstance(TimeZone.getDefault());
-    private String mDescFormat;
-    private TimeZone mTimeZone;
-
-    public TypographicClock(Context context) {
-        this(context, null);
-    }
-
-    public TypographicClock(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TypographicClock(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
-        mResources = context.getResources();
-        mHours = mResources.getStringArray(R.array.type_clock_hours);
-        mMinutes = mResources.getStringArray(R.array.type_clock_minutes);
-        mAccentColor = mResources.getColor(R.color.typeClockAccentColor, null);
-    }
-
-    /**
-     * Call when the time changes to update the text of the time.
-     */
-    public void onTimeChanged() {
-        mTime.setTimeInMillis(System.currentTimeMillis());
-        setContentDescription(DateFormat.format(mDescFormat, mTime));
-        final int hour = mTime.get(Calendar.HOUR) % 12;
-        final int minute = mTime.get(Calendar.MINUTE) % 60;
-
-        // Get the quantity based on the hour for languages like Portuguese and Czech.
-        SpannedString typeTemplate = (SpannedString) mResources.getQuantityText(
-                R.plurals.type_clock_header, hour);
-
-        // Find the "color" annotation and set the foreground color to the accent color.
-        Annotation[] annotations = typeTemplate.getSpans(0, typeTemplate.length(),
-                Annotation.class);
-        SpannableString spanType = new SpannableString(typeTemplate);
-        for (int i = 0; i < annotations.length; i++) {
-            Annotation annotation = annotations[i];
-            String key = annotation.getValue();
-            if (ANNOTATION_COLOR.equals(key)) {
-                spanType.setSpan(new ForegroundColorSpan(mAccentColor),
-                        spanType.getSpanStart(annotation), spanType.getSpanEnd(annotation),
-                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            }
-        }
-
-        setText(TextUtils.expandTemplate(spanType, mHours[hour], mMinutes[minute]));
-    }
-
-    /**
-     * Call when the time zone has changed to update clock time.
-     *
-     * @param timeZone The updated time zone that will be used.
-     */
-    public void onTimeZoneChanged(TimeZone timeZone) {
-        mTimeZone = timeZone;
-        mTime.setTimeZone(timeZone);
-    }
-
-    /**
-     * Sets the accent color used on the clock face.
-     */
-    public void setClockColor(int color) {
-        mAccentColor = color;
-        onTimeChanged();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mTime.setTimeZone(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
-        onTimeChanged();
-    }
-
-    /**
-     * Overriding hasOverlappingRendering as false to improve performance of crossfading.
-     */
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 4fe09a9..665df77 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -26,16 +26,41 @@
  */
 class Bubble {
 
+    private final String mKey;
+    private final BubbleExpandedView.OnBubbleBlockedListener mListener;
+
+    private boolean mInflated;
+
     public BubbleView iconView;
     public BubbleExpandedView expandedView;
-    public String key;
     public NotificationEntry entry;
 
+    Bubble(NotificationEntry e, BubbleExpandedView.OnBubbleBlockedListener listener) {
+        entry = e;
+        mKey = e.key;
+        mListener = listener;
+    }
+
+    /** @deprecated use the other constructor to defer View creation. */
+    @Deprecated
     Bubble(NotificationEntry e, LayoutInflater inflater, BubbleStackView stackView,
             BubbleExpandedView.OnBubbleBlockedListener listener) {
-        entry = e;
-        key = entry.key;
+        this(e, listener);
+        inflate(inflater, stackView);
+    }
 
+    public String getKey() {
+        return mKey;
+    }
+
+    boolean isInflated() {
+        return mInflated;
+    }
+
+    void inflate(LayoutInflater inflater, BubbleStackView stackView) {
+        if (mInflated) {
+            return;
+        }
         iconView = (BubbleView) inflater.inflate(
                 R.layout.bubble_view, stackView, false /* attachToRoot */);
         iconView.setNotif(entry);
@@ -44,12 +69,14 @@
                 R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
         expandedView.setEntry(entry, stackView);
 
-        expandedView.setOnBlockedListener(listener);
+        expandedView.setOnBlockedListener(mListener);
+        mInflated = true;
     }
 
-    public void setEntry(NotificationEntry entry) {
-        key = entry.key;
-        iconView.update(entry);
-        expandedView.update(entry);
+    void setEntry(NotificationEntry entry) {
+        if (mInflated) {
+            iconView.update(entry);
+            expandedView.update(entry);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 5acf3c2..93effed 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -220,6 +220,26 @@
         mSurfaceSynchronizer = synchronizer;
     }
 
+    /**
+     * BubbleStackView is lazily created by this method the first time a Bubble is added. This
+     * method initializes the stack view and adds it to the StatusBar just above the scrim.
+     */
+    private void ensureStackViewCreated() {
+        if (mStackView == null) {
+            mStackView = new BubbleStackView(mContext, mBubbleData, mSurfaceSynchronizer);
+            ViewGroup sbv = mStatusBarWindowController.getStatusBarView();
+            // TODO(b/130237686): When you expand the shade on top of expanded bubble, there is no
+            //  scrim between bubble and the shade
+            int bubblePosition = sbv.indexOfChild(sbv.findViewById(R.id.scrim_behind)) + 1;
+            sbv.addView(mStackView, bubblePosition,
+                    new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            if (mExpandListener != null) {
+                mStackView.setExpandListener(mExpandListener);
+            }
+            mStackView.setOnBlockedListener(this);
+        }
+    }
+
     @Override
     public void onUiModeChanged() {
         if (mStackView != null) {
@@ -325,31 +345,21 @@
     /**
      * Adds or updates a bubble associated with the provided notification entry.
      *
-     * @param notif          the notification associated with this bubble.
+     * @param notif the notification associated with this bubble.
      */
     void updateBubble(NotificationEntry notif) {
         if (mStackView != null && mBubbleData.getBubble(notif.key) != null) {
             // It's an update
             mStackView.updateBubble(notif);
         } else {
-            if (mStackView == null) {
-                mStackView = new BubbleStackView(mContext, mBubbleData, mSurfaceSynchronizer);
-                ViewGroup sbv = mStatusBarWindowController.getStatusBarView();
-                // XXX: Bug when you expand the shade on top of expanded bubble, there is no scrim
-                // between bubble and the shade
-                int bubblePosition = sbv.indexOfChild(sbv.findViewById(R.id.scrim_behind)) + 1;
-                sbv.addView(mStackView, bubblePosition,
-                        new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-                if (mExpandListener != null) {
-                    mStackView.setExpandListener(mExpandListener);
-                }
-                mStackView.setOnBlockedListener(this);
-            }
             // It's new
+            ensureStackViewCreated();
             mStackView.addBubble(notif);
         }
+        Bubble bubble = mBubbleData.getBubble(notif.key);
         if (shouldAutoExpand(notif)) {
-            mStackView.setExpandedBubble(notif);
+            mStackView.setSelectedBubble(bubble);
+            mStackView.setExpanded(true);
         }
         updateVisibility();
     }
@@ -389,11 +399,8 @@
                 return;
             }
             if (shouldAutoBubbleForFlags(mContext, entry) || shouldBubble(entry)) {
-                // TODO: handle group summaries
-                boolean suppressNotification = entry.getBubbleMetadata() != null
-                        && entry.getBubbleMetadata().getSuppressInitialNotification()
-                        && isForegroundApp(entry.notification.getPackageName());
-                entry.setShowInShadeWhenBubble(!suppressNotification);
+                // TODO: handle group summaries?
+                updateShowInShadeForSuppressNotification(entry);
             }
         }
 
@@ -414,7 +421,7 @@
             }
             if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
                     && alertAgain(entry, entry.notification.getNotification())) {
-                entry.setShowInShadeWhenBubble(true);
+                updateShowInShadeForSuppressNotification(entry);
                 entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed
                 updateBubble(entry);
                 mStackView.updateDotVisibility(entry.key);
@@ -581,6 +588,13 @@
                 && isForegroundApp(entry.notification.getPackageName());
     }
 
+    private void updateShowInShadeForSuppressNotification(NotificationEntry entry) {
+        boolean suppressNotification = entry.getBubbleMetadata() != null
+                && entry.getBubbleMetadata().getSuppressNotification()
+                && isForegroundApp(entry.notification.getPackageName());
+        entry.setShowInShadeWhenBubble(!suppressNotification);
+    }
+
     /**
      * Return true if the applications with the package name is running in foreground.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index cf70287..fe3f9d1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -106,7 +106,7 @@
     }
 
     public void addBubble(Bubble b) {
-        mBubbles.put(b.key, b);
+        mBubbles.put(b.getKey(), b);
     }
 
     @Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 6b21526..285d4aab 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -229,6 +229,9 @@
                 true /* singleTaskInstance */);
         addView(mActivityView);
 
+        // Make sure pointer is below activity view
+        bringChildToFront(mPointerView);
+
         setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
             // Keep track of IME displaying because we should not make any adjustments that might
             // cause a config change while the IME is displayed otherwise it'll loose focus.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 53e65e6..1f1a3e4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -441,40 +441,15 @@
      * Sets the bubble that should be expanded and expands if needed.
      *
      * @param key the {@link NotificationEntry#key} associated with the bubble to expand.
+     * @deprecated replaced by setSelectedBubble(Bubble) + setExpanded(true)
      */
+    @Deprecated
     void setExpandedBubble(String key) {
         Bubble bubbleToExpand = mBubbleData.getBubble(key);
-        if (mIsExpanded && !bubbleToExpand.equals(mExpandedBubble)) {
-            // Previously expanded, notify that this bubble is no longer expanded
-            notifyExpansionChanged(mExpandedBubble.entry, false /* expanded */);
-        }
-        Bubble prevBubble = mExpandedBubble;
-        mExpandedBubble = bubbleToExpand;
-        if (!mIsExpanded) {
-            // If we weren't previously expanded we should animate open.
-            animateExpansion(true /* expand */);
-            logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
-            mExpandedBubble.entry.setShowInShadeWhenBubble(false);
-            notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
-        } else {
-            // Make the container of the expanded view transparent before removing the expanded view
-            // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
-            // expanded view becomes visible on the screen. See b/126856255
-            mExpandedViewContainer.setAlpha(0.0f);
-
-            mSurfaceSynchronizer.syncSurfaceAndRun(new Runnable() {
-                @Override
-                public void run() {
-                    updateExpandedBubble();
-                    updatePointerPosition();
-                    requestUpdate();
-                    logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
-                    logBubbleEvent(mExpandedBubble,
-                            StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
-                    mExpandedBubble.entry.setShowInShadeWhenBubble(false);
-                    notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
-                }
-            });
+        if (bubbleToExpand != null) {
+            setSelectedBubble(bubbleToExpand);
+            bubbleToExpand.entry.setShowInShadeWhenBubble(false);
+            setExpanded(true);
         }
     }
 
@@ -492,6 +467,57 @@
     }
 
     /**
+     * Changes the currently selected bubble. If the stack is already expanded, the newly selected
+     * bubble will be shown immediately. This does not change the expanded state or change the
+     * position of any bubble.
+     */
+    public void setSelectedBubble(Bubble bubbleToSelect) {
+        if (mExpandedBubble != null && mExpandedBubble.equals(bubbleToSelect)) {
+            return;
+        }
+        final Bubble previouslySelected = mExpandedBubble;
+        mExpandedBubble = bubbleToSelect;
+        if (mIsExpanded) {
+            // Make the container of the expanded view transparent before removing the expanded view
+            // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
+            // expanded view becomes visible on the screen. See b/126856255
+            mExpandedViewContainer.setAlpha(0.0f);
+            mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
+                updateExpandedBubble();
+                updatePointerPosition();
+                requestUpdate();
+                logBubbleEvent(previouslySelected, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
+                logBubbleEvent(bubbleToSelect, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+                notifyExpansionChanged(previouslySelected.entry, false /* expanded */);
+                notifyExpansionChanged(bubbleToSelect.entry, true /* expanded */);
+            });
+        }
+    }
+
+    /**
+     * Changes the expanded state of the stack.
+     *
+     * @param expanded whether the bubble stack should appear expanded
+     */
+    public void setExpanded(boolean expanded) {
+        if (expanded == mIsExpanded) {
+            return;
+        }
+        if (mIsExpanded) {
+            // Collapse the stack
+            animateExpansion(false /* expand */);
+            logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
+        } else {
+            // Expand the stack
+            animateExpansion(true /* expand */);
+            // TODO: move next line to BubbleData
+            logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+            logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
+        }
+        notifyExpansionChanged(mExpandedBubble.entry, mIsExpanded);
+    }
+
+    /**
      * Adds a bubble to the top of the stack.
      *
      * @param entry the notification to add to the stack of bubbles.
@@ -652,7 +678,10 @@
      * Collapses the stack of bubbles.
      * <p>
      * Must be called from the main thread.
+     *
+     * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
      */
+    @Deprecated
     @MainThread
     public void collapseStack() {
         if (mIsExpanded) {
@@ -663,6 +692,11 @@
         }
     }
 
+    /**
+     * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
+     */
+    @Deprecated
+    @MainThread
     void collapseStack(Runnable endRunnable) {
         collapseStack();
         // TODO - use the runnable at end of animation
@@ -673,7 +707,10 @@
      * Expands the stack of bubbles.
      * <p>
      * Must be called from the main thread.
+     *
+     * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
      */
+    @Deprecated
     @MainThread
     public void expandStack() {
         if (!mIsExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index a74c328..05665b5 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -34,6 +34,7 @@
 import com.android.internal.colorextraction.types.Tonal;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -46,7 +47,8 @@
  * ColorExtractor aware of wallpaper visibility
  */
 @Singleton
-public class SysuiColorExtractor extends ColorExtractor implements Dumpable {
+public class SysuiColorExtractor extends ColorExtractor implements Dumpable,
+        ConfigurationController.ConfigurationListener {
     private static final String TAG = "SysuiColorExtractor";
     private final Tonal mTonal;
     private boolean mWallpaperVisible;
@@ -55,15 +57,17 @@
     private final GradientColors mWpHiddenColors;
 
     @Inject
-    public SysuiColorExtractor(Context context) {
-        this(context, new Tonal(context), true);
+    public SysuiColorExtractor(Context context, ConfigurationController configurationController) {
+        this(context, new Tonal(context), configurationController, true);
     }
 
     @VisibleForTesting
-    public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) {
+    public SysuiColorExtractor(Context context, ExtractionType type,
+            ConfigurationController configurationController, boolean registerVisibility) {
         super(context, type, false /* immediately */);
         mTonal = type instanceof Tonal ? (Tonal) type : new Tonal(context);
         mWpHiddenColors = new GradientColors();
+        configurationController.addCallback(this);
 
         WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
         updateDefaultGradients(systemColors);
@@ -113,8 +117,21 @@
         }
     }
 
-    @VisibleForTesting
-    GradientColors getFallbackColors() {
+    @Override
+    public void onUiModeChanged() {
+        WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
+        updateDefaultGradients(systemColors);
+    }
+
+    /**
+     * Colors the should be using for scrims.
+     *
+     * They will be:
+     * - A light gray if the wallpaper is light
+     * - A dark gray if the wallpaper is very dark or we're in night mode.
+     * - Black otherwise
+     */
+    public GradientColors getNeutralColors() {
         return mWpHiddenColors;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 77180f8..831d074 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -228,9 +228,9 @@
     /** Dump current state */
     public void dump(PrintWriter pw) {
         for (TriggerSensor s : mSensors) {
-            pw.print("Sensor: "); pw.println(s.toString());
+            pw.print("  Sensor: "); pw.println(s.toString());
         }
-        pw.print("ProxSensor: "); pw.println(mProxSensor.toString());
+        pw.print("  ProxSensor: "); pw.println(mProxSensor.toString());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 7a3f3be..411536c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -35,7 +35,6 @@
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
-import android.graphics.Point;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
@@ -73,7 +72,7 @@
 import com.android.internal.R;
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.TelephonyIntents;
@@ -1503,7 +1502,7 @@
         private final MyAdapter mAdapter;
         private MultiListLayout mGlobalActionsLayout;
         private Drawable mBackgroundDrawable;
-        private final ColorExtractor mColorExtractor;
+        private final SysuiColorExtractor mColorExtractor;
         private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
         private boolean mKeyguardShowing;
         private boolean mShowing;
@@ -1582,7 +1581,7 @@
 
             if (!shouldUsePanel()) {
                 if (mBackgroundDrawable == null) {
-                    mBackgroundDrawable = new GradientDrawable(mContext);
+                    mBackgroundDrawable = new ScrimDrawable();
                 }
                 mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
             } else {
@@ -1610,16 +1609,9 @@
             super.onStart();
             mGlobalActionsLayout.updateList();
 
-            if (mBackgroundDrawable instanceof GradientDrawable) {
-                Point displaySize = new Point();
-                mContext.getDisplay().getRealSize(displaySize);
+            if (mBackgroundDrawable instanceof ScrimDrawable) {
                 mColorExtractor.addOnColorsChangedListener(this);
-                ((GradientDrawable) mBackgroundDrawable)
-                        .setScreenSize(displaySize.x, displaySize.y);
-                GradientColors colors = mColorExtractor.getColors(
-                        mKeyguardShowing
-                                ? WallpaperManager.FLAG_LOCK
-                                : WallpaperManager.FLAG_SYSTEM);
+                GradientColors colors = mColorExtractor.getNeutralColors();
                 updateColors(colors, false /* animate */);
             }
         }
@@ -1630,10 +1622,10 @@
          * @param animate Interpolates gradient if true, just sets otherwise.
          */
         private void updateColors(GradientColors colors, boolean animate) {
-            if (!(mBackgroundDrawable instanceof GradientDrawable)) {
+            if (!(mBackgroundDrawable instanceof ScrimDrawable)) {
                 return;
             }
-            ((GradientDrawable) mBackgroundDrawable).setColors(colors, animate);
+            ((ScrimDrawable) mBackgroundDrawable).setColor(colors.getMainColor(), animate);
             View decorView = getWindow().getDecorView();
             if (colors.supportsDarkText()) {
                 decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 4cf58b7..4065d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -19,9 +19,7 @@
 
 import android.app.Dialog;
 import android.app.KeyguardManager;
-import android.app.WallpaperManager;
 import android.content.Context;
-import android.graphics.Point;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -31,7 +29,7 @@
 
 import com.android.internal.R;
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysUiServiceProvider;
@@ -87,7 +85,7 @@
 
     @Override
     public void showShutdownUi(boolean isReboot, String reason) {
-        GradientDrawable background = new GradientDrawable(mContext);
+        ScrimDrawable background = new ScrimDrawable();
         background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
 
         Dialog d = new Dialog(mContext,
@@ -129,12 +127,8 @@
         message.setTextColor(color);
         if (isReboot) message.setText(R.string.reboot_to_reset_message);
 
-        Point displaySize = new Point();
-        mContext.getDisplay().getRealSize(displaySize);
-        GradientColors colors = Dependency.get(SysuiColorExtractor.class).getColors(
-                onKeyguard ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM);
-        background.setColors(colors, false);
-        background.setScreenSize(displaySize.x, displaySize.y);
+        GradientColors colors = Dependency.get(SysuiColorExtractor.class).getNeutralColors();
+        background.setColor(colors.getMainColor(), false);
 
         d.show();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
index d1939d0..477e7d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
@@ -85,9 +85,7 @@
             Bitmap bitmap = bitmaps[0];
             if (bitmap != null) {
                 int[] histogram = processHistogram(bitmap);
-                Float val = computePercentile85(bitmap, histogram);
-                bitmaps[0] = null;
-                return val;
+                return computePercentile85(bitmap, histogram);
             }
             Log.e(TAG, "Per85ComputeTask: Can't get bitmap");
             return DEFAULT_PER85;
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 10f727b..e92aa51 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -22,15 +22,19 @@
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.media.AudioAttributes;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.text.Annotation;
 import android.text.Layout;
@@ -547,9 +551,15 @@
         updateNotification();
     }
 
-    private void showStartSaverConfirmation(boolean confirmOnly) {
+    private void showStartSaverConfirmation(Bundle extras) {
         if (mSaverConfirmation != null) return;
         final SystemUIDialog d = new SystemUIDialog(mContext);
+        final boolean confirmOnly = extras.getBoolean(BatterySaverUtils.EXTRA_CONFIRM_TEXT_ONLY);
+        final int batterySaverTriggerMode =
+                extras.getInt(BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER,
+                        PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
+        final int batterySaverTriggerLevel =
+                extras.getInt(BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL, 0);
         d.setMessage(getBatterySaverDescription());
 
         // Sad hack for http://b/78261259 and http://b/78298335. Otherwise "Battery" may be split
@@ -563,14 +573,25 @@
         if (confirmOnly) {
             d.setTitle(R.string.battery_saver_confirmation_title_generic);
             d.setPositiveButton(com.android.internal.R.string.confirm_battery_saver,
-                    (dialog, which) -> Secure.putInt(
-                            mContext.getContentResolver(),
-                            Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
-                            1));
+                    (dialog, which) -> {
+                        final ContentResolver resolver = mContext.getContentResolver();
+                        Secure.putInt(
+                                resolver,
+                                Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
+                                1);
+                        Settings.Global.putInt(
+                                resolver,
+                                Global.AUTOMATIC_POWER_SAVE_MODE,
+                                batterySaverTriggerMode);
+                        Settings.Global.putInt(
+                                resolver,
+                                Global.LOW_POWER_MODE_TRIGGER_LEVEL,
+                                batterySaverTriggerLevel);
+                    });
         } else {
             d.setTitle(R.string.battery_saver_confirmation_title);
             d.setPositiveButton(R.string.battery_saver_confirmation_ok,
-                (dialog, which) -> setSaverMode(true, false));
+                    (dialog, which) -> setSaverMode(true, false));
             d.setNegativeButton(android.R.string.cancel, null);
         }
         d.setShowForAllUsers(true);
@@ -731,7 +752,7 @@
                 dismissLowBatteryNotification();
             } else if (action.equals(ACTION_SHOW_START_SAVER_CONFIRMATION)) {
                 dismissLowBatteryNotification();
-                showStartSaverConfirmation(intent.getBooleanExtra(EXTRA_CONFIRM_ONLY, false));
+                showStartSaverConfirmation(intent.getExtras());
             } else if (action.equals(ACTION_DISMISSED_WARNING)) {
                 dismissLowBatteryWarning();
             } else if (ACTION_CLICKED_TEMP_WARNING.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 2956ad0..daaee4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -41,6 +41,7 @@
 import com.android.systemui.qs.tiles.NfcTile;
 import com.android.systemui.qs.tiles.NightDisplayTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.qs.tiles.UiModeNightTile;
 import com.android.systemui.qs.tiles.UserTile;
 import com.android.systemui.qs.tiles.WifiTile;
 import com.android.systemui.qs.tiles.WorkModeTile;
@@ -73,6 +74,7 @@
     private final Provider<NightDisplayTile> mNightDisplayTileProvider;
     private final Provider<NfcTile> mNfcTileProvider;
     private final Provider<GarbageMonitor.MemoryTile> mMemoryTileProvider;
+    private final Provider<UiModeNightTile> mUiModeNightTileProvider;
 
     private QSTileHost mHost;
 
@@ -94,7 +96,8 @@
             Provider<DataSaverTile> dataSaverTileProvider,
             Provider<NightDisplayTile> nightDisplayTileProvider,
             Provider<NfcTile> nfcTileProvider,
-            Provider<GarbageMonitor.MemoryTile> memoryTileProvider) {
+            Provider<GarbageMonitor.MemoryTile> memoryTileProvider,
+            Provider<UiModeNightTile> uiModeNightTileProvider) {
         mWifiTileProvider = wifiTileProvider;
         mBluetoothTileProvider = bluetoothTileProvider;
         mCellularTileProvider = cellularTileProvider;
@@ -113,6 +116,7 @@
         mNightDisplayTileProvider = nightDisplayTileProvider;
         mNfcTileProvider = nfcTileProvider;
         mMemoryTileProvider = memoryTileProvider;
+        mUiModeNightTileProvider = uiModeNightTileProvider;
     }
 
     public void setHost(QSTileHost host) {
@@ -164,6 +168,8 @@
                 return mNightDisplayTileProvider.get();
             case "nfc":
                 return mNfcTileProvider.get();
+            case "dark":
+                return mUiModeNightTileProvider.get();
         }
 
         // Intent tiles.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index d40973b..a732a25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -40,7 +40,6 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
 import android.widget.Switch;
 
 import com.android.settingslib.Utils;
@@ -63,6 +62,7 @@
     private boolean mTileState;
     private boolean mCollapsedView;
     private boolean mClicked;
+    private boolean mShowRippleEffect = true;
 
     private final ImageView mBg;
     private final int mColorActive;
@@ -209,6 +209,7 @@
             mCircleColor = circleColor;
         }
 
+        mShowRippleEffect = state.showRippleEffect;
         setClickable(state.state != Tile.STATE_UNAVAILABLE);
         setLongClickable(state.handlesLongClick);
         mIcon.setIcon(state, allowAnimations);
@@ -254,7 +255,7 @@
     @Override
     public void setClickable(boolean clickable) {
         super.setClickable(clickable);
-        setBackground(clickable ? mRipple : null);
+        setBackground(clickable && mShowRippleEffect ? mRipple : null);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index c664a20..d62f10d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -16,6 +16,7 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
+import android.provider.Settings.Secure;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
@@ -23,6 +24,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.BatteryController;
 
@@ -32,6 +34,7 @@
         BatteryController.BatteryStateChangeCallback {
 
     private final BatteryController mBatteryController;
+    private final SecureSetting mSetting;
 
     private int mLevel;
     private boolean mPowerSave;
@@ -45,6 +48,12 @@
         super(host);
         mBatteryController = batteryController;
         mBatteryController.observe(getLifecycle(), this);
+        mSetting = new SecureSetting(mContext, mHandler, Secure.LOW_POWER_WARNING_ACKNOWLEDGED) {
+            @Override
+            protected void handleValueChanged(int value, boolean observedChange) {
+                handleRefreshState(null);
+            }
+        };
     }
 
     @Override
@@ -53,12 +62,19 @@
     }
 
     @Override
+    protected void handleDestroy() {
+        super.handleDestroy();
+        mSetting.setListening(false);
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsEvent.QS_BATTERY_TILE;
     }
 
     @Override
     public void handleSetListening(boolean listening) {
+        mSetting.setListening(listening);
     }
 
     @Override
@@ -88,6 +104,7 @@
         state.contentDescription = state.label;
         state.value = mPowerSave;
         state.expandedAccessibilityClassName = Switch.class.getName();
+        state.showRippleEffect = mSetting.getValue() == 0;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
new file mode 100644
index 0000000..8d2f895
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -0,0 +1,104 @@
+/*
+ * 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.qs.tiles;
+
+import android.app.UiModeManager;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.widget.Switch;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
+import javax.inject.Inject;
+
+/**
+ * Quick Settings tile for: Night Mode / Dark Theme / Dark Mode.
+ *
+ * The string id of this tile is "dark" because "night" was already
+ * taken by {@link NightDisplayTile}.
+ */
+public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements
+        ConfigurationController.ConfigurationListener {
+
+    private final Icon mIcon = ResourceIcon.get(
+            com.android.internal.R.drawable.ic_qs_ui_mode_night);
+    private UiModeManager mUiModeManager;
+
+    @Inject
+    public UiModeNightTile(QSHost host, ConfigurationController configurationController) {
+        super(host);
+        mUiModeManager = mContext.getSystemService(UiModeManager.class);
+        configurationController.observe(getLifecycle(), this);
+    }
+
+    @Override
+    public void onUiModeChanged() {
+        refreshState();
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    protected void handleClick() {
+        boolean newState = !mState.value;
+        mUiModeManager.setNightMode(newState ? UiModeManager.MODE_NIGHT_YES
+                : UiModeManager.MODE_NIGHT_NO);
+        refreshState(newState);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        boolean nightMode = (mContext.getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+
+        state.value = nightMode;
+        state.label = mContext.getString(R.string.quick_settings_ui_mode_night_label);
+        state.contentDescription = state.label;
+        state.icon = mIcon;
+        state.expandedAccessibilityClassName = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.QS_UI_MODE_NIGHT;
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+    }
+
+    @Override
+    protected void handleSetListening(boolean listening) {
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return getState().label;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 4d6693f..00aef9a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -28,6 +28,9 @@
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
 
 import android.annotation.FloatRange;
 import android.content.BroadcastReceiver;
@@ -52,6 +55,7 @@
 import android.view.MotionEvent;
 
 import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysUiServiceProvider;
@@ -60,7 +64,10 @@
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
 import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.CallbackController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -107,6 +114,7 @@
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private @InteractionType int mInteractionFlags;
+    private @SystemUiStateFlags int mSysUiStateFlags;
     private boolean mBound;
     private boolean mIsEnabled;
     private int mCurrentBoundedUserId = -1;
@@ -368,6 +376,9 @@
             }
             dispatchNavButtonBounds();
 
+            // Update the systemui state flags
+            updateSystemUiStateFlags();
+
             notifyConnectionChanged();
         }
 
@@ -394,19 +405,29 @@
 
     private final DeviceProvisionedListener mDeviceProvisionedCallback =
                 new DeviceProvisionedListener() {
-            @Override
-            public void onUserSetupChanged() {
-                if (mDeviceProvisionedController.isCurrentUserSetup()) {
-                    internalConnectToCurrentUser();
-                }
-            }
 
-            @Override
-            public void onUserSwitched() {
-                mConnectionBackoffAttempts = 0;
+        @Override
+        public void onDeviceProvisionedChanged() {
+            /*
+            on initialize, keep track of the previous gestural state (nothing is enabled by default)
+            restore to a non gestural state if device is not provisioned
+            once the device is provisioned, restore to the original state
+             */
+        }
+
+        @Override
+        public void onUserSetupChanged() {
+            if (mDeviceProvisionedController.isCurrentUserSetup()) {
                 internalConnectToCurrentUser();
             }
-        };
+        }
+
+        @Override
+        public void onUserSwitched() {
+            mConnectionBackoffAttempts = 0;
+            internalConnectToCurrentUser();
+        }
+    };
 
     // This is the death handler for the binder from the launcher service
     private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
@@ -455,6 +476,45 @@
         }
     }
 
+    public void setSystemUiStateFlag(int flag, boolean enabled) {
+        int newState = mSysUiStateFlags;
+        if (enabled) {
+            newState |= flag;
+        } else {
+            newState &= ~flag;
+        }
+        if (mSysUiStateFlags != newState) {
+            mSysUiStateFlags = newState;
+            notifySystemUiStateFlags(mSysUiStateFlags);
+        }
+    }
+
+    private void updateSystemUiStateFlags() {
+        final NavigationBarController navBar = Dependency.get(NavigationBarController.class);
+        final NavigationBarFragment navBarFragment = navBar.getDefaultNavigationBarFragment();
+        final StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+        final boolean panelExpanded = statusBar != null && statusBar.getPanel() != null
+                && statusBar.getPanel().isFullyExpanded();
+        mSysUiStateFlags = 0;
+        mSysUiStateFlags |= ActivityManagerWrapper.getInstance().isScreenPinningActive()
+                ? SYSUI_STATE_SCREEN_PINNING : 0;
+        mSysUiStateFlags |= (navBarFragment == null || !navBarFragment.isNavBarWindowVisible())
+                ? SYSUI_STATE_NAV_BAR_HIDDEN : 0;
+        mSysUiStateFlags |= panelExpanded
+                ? SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED : 0;
+        notifySystemUiStateFlags(mSysUiStateFlags);
+    }
+
+    private void notifySystemUiStateFlags(int flags) {
+        try {
+            if (mOverviewProxy != null) {
+                mOverviewProxy.onSystemUiStateChanged(flags);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG_OPS, "Failed to notify sysui state change", e);
+        }
+    }
+
     /**
      * Sets the navbar region which can receive touch inputs
      */
@@ -631,7 +691,9 @@
 
     public void notifyAssistantVisibilityChanged(float visibility) {
         try {
-            mOverviewProxy.onAssistantVisibilityChanged(visibility);
+            if (mOverviewProxy != null) {
+                mOverviewProxy.onAssistantVisibilityChanged(visibility);
+            }
         } catch (RemoteException e) {
             Log.e(TAG_OPS, "Failed to call onAssistantVisibilityChanged()", e);
         }
@@ -657,6 +719,7 @@
         pw.print("  quickStepIntentResolved="); pw.println(isEnabled());
         pw.print("  navBarMode=");
         pw.println(QuickStepContract.getCurrentInteractionMode(mContext));
+        pw.print("  mSysUiStateFlags="); pw.println(mSysUiStateFlags);
     }
 
     public interface OverviewProxyListener {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 34f3c60..33a2acf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -64,6 +64,7 @@
 import com.android.systemui.R;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 
 import java.io.PrintWriter;
@@ -339,7 +340,7 @@
     }
 
     public void onConnectedToLauncher() {
-        if (!ONBOARDING_ENABLED) {
+        if (!ONBOARDING_ENABLED || QuickStepContract.isGesturalMode(mContext)) {
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index f796793..07391ed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
 import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
 import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
 
@@ -44,6 +45,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -59,6 +61,7 @@
 
     private final AccessibilityManager mAccessibilityService;
     private final WindowManager mWindowManager;
+    private final OverviewProxyService mOverviewProxyService;
 
     private RequestWindowView mRequestWindow;
 
@@ -71,6 +74,7 @@
                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
         mWindowManager = (WindowManager)
                 mContext.getSystemService(Context.WINDOW_SERVICE);
+        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
     }
 
     public void clearPrompt() {
@@ -125,6 +129,7 @@
         if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {
             try {
                 ActivityTaskManager.getService().startSystemLockTaskMode(taskId);
+                mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING, true);
             } catch (RemoteException e) {}
         }
         clearPrompt();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index a87e50c..3441591 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -83,7 +83,7 @@
 
     private final int mSlowThreshold;
     private final int mFastThreshold;
-    private LockIcon mLockIcon;
+    private final LockIcon mLockIcon;
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     private String mRestingIndication;
@@ -539,7 +539,6 @@
 
     protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
         public static final int HIDE_DELAY_MS = 5000;
-        private int mLastSuccessiveErrorMessage = -1;
 
         @Override
         public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
@@ -577,20 +576,14 @@
             if (!updateMonitor.isUnlockingWithBiometricAllowed()) {
                 return;
             }
+            animatePadlockError();
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
                         mInitialTextColorState);
             } else if (updateMonitor.isScreenOn()) {
-                mLockIcon.setTransientBiometricsError(true);
                 showTransientIndication(helpString);
                 hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
-                mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
-                        TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
             }
-            // Help messages indicate that there was actually a try since the last error, so those
-            // are not two successive error messages anymore.
-            mLastSuccessiveErrorMessage = -1;
         }
 
         @Override
@@ -600,15 +593,9 @@
             if (shouldSuppressBiometricError(msgId, biometricSourceType, updateMonitor)) {
                 return;
             }
+            animatePadlockError();
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                // When swiping up right after receiving a biometric error, the bouncer calls
-                // authenticate leading to the same message being shown again on the bouncer.
-                // We want to avoid this, as it may confuse the user when the message is too
-                // generic.
-                if (mLastSuccessiveErrorMessage != msgId) {
-                    mStatusBarKeyguardViewManager.showBouncerMessage(errString,
-                            mInitialTextColorState);
-                }
+                mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
             } else if (updateMonitor.isScreenOn()) {
                 showTransientIndication(errString);
                 // We want to keep this message around in case the screen was off
@@ -616,7 +603,13 @@
             } else {
                 mMessageToShowOnScreenOn = errString;
             }
-            mLastSuccessiveErrorMessage = msgId;
+        }
+
+        private void animatePadlockError() {
+            mLockIcon.setTransientBiometricsError(true);
+            mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
+                    TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
         }
 
         private boolean shouldSuppressBiometricError(int msgId,
@@ -670,21 +663,19 @@
         @Override
         public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
             super.onBiometricAuthenticated(userId, biometricSourceType);
-            mLastSuccessiveErrorMessage = -1;
             mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
         }
 
         @Override
-        public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
-            super.onBiometricAuthFailed(biometricSourceType);
-            mLastSuccessiveErrorMessage = -1;
-        }
-
-        @Override
         public void onUserUnlocked() {
             if (mVisible) {
                 updateIndication(false);
             }
         }
+
+        @Override
+        public void onKeyguardBouncerChanged(boolean bouncer) {
+            mLockIcon.setBouncerVisible(bouncer);
+        }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 2bb6e3e..c833ded 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -67,7 +67,10 @@
         mContext = context;
         mHandler = handler;
         mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
-        getComponent(mContext, CommandQueue.class).addCallback(this);
+        CommandQueue commandQueue = getComponent(mContext, CommandQueue.class);
+        if (commandQueue != null) {
+            commandQueue.addCallback(this);
+        }
     }
 
     @Override
@@ -206,4 +209,9 @@
         NavigationBarFragment navBar = mNavigationBars.get(DEFAULT_DISPLAY);
         return (navBar == null) ? null : (NavigationBarView) navBar.getView();
     }
+
+    /** @return {@link NavigationBarFragment} on the default display. */
+    public NavigationBarFragment getDefaultNavigationBarFragment() {
+        return mNavigationBars.get(DEFAULT_DISPLAY);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index cf6e64c..04f1c32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -16,61 +16,33 @@
 
 package com.android.systemui.statusbar;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Display;
 import android.view.View;
-import android.view.WindowManager;
 
 import androidx.core.graphics.ColorUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
 
 /**
  * A view which can draw a scrim
  */
-public class ScrimView extends View implements ConfigurationController.ConfigurationListener {
-    private static final String TAG = "ScrimView";
+public class ScrimView extends View {
     private final ColorExtractor.GradientColors mColors;
-    private int mDensity;
     private float mViewAlpha = 1.0f;
-    private ValueAnimator mAlphaAnimator;
     private Drawable mDrawable;
     private PorterDuffColorFilter mColorFilter;
     private int mTintColor;
-    private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener = animation -> {
-        if (mDrawable == null) {
-            Log.w(TAG, "Trying to animate null drawable");
-            return;
-        }
-        mDrawable.setAlpha((int) (255 * (float) animation.getAnimatedValue()));
-    };
-    private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mAlphaAnimator = null;
-        }
-    };
     private Runnable mChangeRunnable;
-    private int mCornerRadius;
 
     public ScrimView(Context context) {
         this(context, null);
@@ -87,47 +59,10 @@
     public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
-        mDrawable = new GradientDrawable(context);
+        mDrawable = new ScrimDrawable();
         mDrawable.setCallback(this);
         mColors = new ColorExtractor.GradientColors();
-        updateScreenSize();
         updateColorWithTint(false);
-        initView();
-        final Configuration currentConfig = mContext.getResources().getConfiguration();
-        mDensity = currentConfig.densityDpi;
-    }
-
-    private void initView() {
-        mCornerRadius = getResources().getDimensionPixelSize(
-                Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        int densityDpi = newConfig.densityDpi;
-        if (mDensity != densityDpi) {
-            mDensity = densityDpi;
-            initView();
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        // We need to know about configuration changes to update the gradient size
-        // since it's independent from view bounds.
-        ConfigurationController config = Dependency.get(ConfigurationController.class);
-        config.addCallback(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        ConfigurationController config = Dependency.get(ConfigurationController.class);
-        config.removeCallback(this);
     }
 
     @Override
@@ -142,7 +77,6 @@
         mDrawable.setCallback(this);
         mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
         mDrawable.setAlpha((int) (255 * mViewAlpha));
-        updateScreenSize();
         invalidate();
     }
 
@@ -200,15 +134,13 @@
     }
 
     private void updateColorWithTint(boolean animated) {
-        if (mDrawable instanceof GradientDrawable) {
+        if (mDrawable instanceof ScrimDrawable) {
             // Optimization to blend colors and avoid a color filter
-            GradientDrawable drawable = (GradientDrawable) mDrawable;
+            ScrimDrawable drawable = (ScrimDrawable) mDrawable;
             float tintAmount = Color.alpha(mTintColor) / 255f;
             int mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor,
                     tintAmount);
-            int secondaryTinted = ColorUtils.blendARGB(mColors.getSecondaryColor(), mTintColor,
-                    tintAmount);
-            drawable.setColors(mainTinted, secondaryTinted, animated);
+            drawable.setColor(mainTinted, animated);
         } else {
             boolean hasAlpha = Color.alpha(mTintColor) != 0;
             if (hasAlpha) {
@@ -250,10 +182,6 @@
         if (alpha != mViewAlpha) {
             mViewAlpha = alpha;
 
-            if (mAlphaAnimator != null) {
-                mAlphaAnimator.cancel();
-            }
-
             mDrawable.setAlpha((int) (255 * alpha));
             if (mChangeRunnable != null) {
                 mChangeRunnable.run();
@@ -270,27 +198,6 @@
     }
 
     @Override
-    public void onConfigChanged(Configuration newConfig) {
-        updateScreenSize();
-    }
-
-    private void updateScreenSize() {
-        if (mDrawable instanceof GradientDrawable) {
-            WindowManager wm = mContext.getSystemService(WindowManager.class);
-            if (wm == null) {
-                Log.w(TAG, "Can't resize gradient drawable to fit the screen");
-                return;
-            }
-            Display display = wm.getDefaultDisplay();
-            if (display != null) {
-                Point size = new Point();
-                display.getRealSize(size);
-                ((GradientDrawable) mDrawable).setScreenSize(size.x, size.y);
-            }
-        }
-    }
-
-    @Override
     protected boolean canReceivePointerEvents() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 3516279..23e2d27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -197,7 +197,7 @@
     private boolean updateState(WifiIconState state) {
         setContentDescription(state.contentDescription);
         if (mState.resId != state.resId && state.resId >= 0) {
-            mWifiIcon.setImageDrawable(mContext.getDrawable(mState.resId));
+            mWifiIcon.setImageDrawable(mContext.getDrawable(state.resId));
         }
 
         mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
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 d11eab7..562e535 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
@@ -401,7 +401,11 @@
         @Override
         public void getOutline(View view, Outline outline) {
             if (mAmbientState.isDarkAtAll() || !mShowDarkShelf) {
-                outline.setRoundRect(mBackgroundAnimationRect, mCornerRadius);
+                float xProgress = mDarkXInterpolator.getInterpolation(
+                        (1 - mLinearDarkAmount) * mBackgroundXFactor);
+                outline.setRoundRect(mBackgroundAnimationRect,
+                        MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius,
+                                xProgress));
             } else {
                 ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 2e85fea..ce8463e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -367,16 +367,11 @@
     @Override
     public void onFinishedGoingToSleep(int why) {
         Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
-        if (mPendingAuthenticatedUserId != -1) {
-
+        BiometricSourceType pendingType = mPendingAuthenticatedBioSourceType;
+        int pendingUserId = mPendingAuthenticatedUserId;
+        if (pendingUserId != -1 && pendingType != null) {
             // Post this to make sure it's executed after the device is fully locked.
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    onBiometricAuthenticated(mPendingAuthenticatedUserId,
-                            mPendingAuthenticatedBioSourceType);
-                }
-            });
+            mHandler.post(() -> onBiometricAuthenticated(pendingUserId, pendingType));
         }
         mPendingAuthenticatedUserId = -1;
         mPendingAuthenticatedBioSourceType = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 3a6756b..79bf6b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -140,6 +141,7 @@
     private WindowManager.LayoutParams mEdgePanelLp;
 
     public EdgeBackGestureHandler(Context context, OverviewProxyService overviewProxyService) {
+        final Resources res = context.getResources();
         mContext = context;
         mDisplayId = context.getDisplayId();
         mMainExecutor = context.getMainExecutor();
@@ -148,10 +150,9 @@
 
         mEdgeWidth = QuickStepContract.getEdgeSensitivityWidth(context);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mSwipeThreshold = context.getResources()
-                .getDimension(R.dimen.navigation_edge_action_drag_threshold);
+        mSwipeThreshold = res.getDimension(R.dimen.navigation_edge_action_drag_threshold);
 
-        mNavBarHeight = context.getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
+        mNavBarHeight = res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 6ebd6b3..3cc4a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -57,8 +57,10 @@
     private int mDensity;
     private boolean mPulsing;
     private boolean mDozing;
+    private boolean mBouncerVisible;
     private boolean mLastDozing;
     private boolean mLastPulsing;
+    private boolean mLastBouncerVisible;
 
     private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
     private float mDarkAmount;
@@ -109,9 +111,9 @@
         int state = getState();
         mIsFaceUnlockState = state == STATE_SCANNING_FACE;
         if (state != mLastState || mLastDozing != mDozing || mLastPulsing != mPulsing
-                || mLastScreenOn != mScreenOn || force) {
+                || mLastScreenOn != mScreenOn || mLastBouncerVisible != mBouncerVisible || force) {
             int iconAnimRes = getAnimationResForTransition(mLastState, state, mLastPulsing,
-                    mPulsing, mLastDozing, mDozing);
+                    mPulsing, mLastDozing, mDozing, mBouncerVisible);
             boolean isAnim = iconAnimRes != -1;
 
             Drawable icon;
@@ -159,6 +161,7 @@
             mLastScreenOn = mScreenOn;
             mLastDozing = mDozing;
             mLastPulsing = mPulsing;
+            mLastBouncerVisible = mBouncerVisible;
         }
 
         setVisibility(mDozing && !mPulsing ? GONE : VISIBLE);
@@ -231,8 +234,8 @@
     }
 
     private static int getAnimationResForTransition(int oldState, int newState,
-            boolean wasPulsing, boolean pulsing,
-            boolean wasDozing, boolean dozing) {
+            boolean wasPulsing, boolean pulsing, boolean wasDozing, boolean dozing,
+            boolean bouncerVisible) {
 
         // Never animate when screen is off
         if (dozing && !pulsing) {
@@ -249,7 +252,7 @@
             return com.android.internal.R.anim.lock_unlock;
         } else if (justLocked) {
             return com.android.internal.R.anim.lock_lock;
-        } else if (newState == STATE_SCANNING_FACE) {
+        } else if (newState == STATE_SCANNING_FACE && bouncerVisible) {
             return com.android.internal.R.anim.lock_scanning;
         } else if (!wasPulsing && pulsing && newState != STATE_LOCK_OPEN) {
             return com.android.internal.R.anim.lock_in;
@@ -298,4 +301,15 @@
         int color = ColorUtils.blendARGB(Color.TRANSPARENT, Color.WHITE, mDarkAmount);
         drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
     }
+
+    /**
+     * If bouncer is visible or not.
+     */
+    public void setBouncerVisible(boolean bouncerVisible) {
+        if (mBouncerVisible == bouncerVisible) {
+            return;
+        }
+        mBouncerVisible = bouncerVisible;
+        update();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 1d87a8b..443cc43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -98,8 +98,10 @@
         // Short-circuiting from UserManager. Needs to be extracted because of SystemUI boolean flag
         // qs_show_user_switcher_for_single_user
 
+        // The default in UserManager is to show the switcher. We want to not show it unless the
+        // user explicitly requests it in Settings
         final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.USER_SWITCHER_ENABLED, 1) != 0;
+                Settings.Global.USER_SWITCHER_ENABLED, 0) != 0;
 
         if (!UserManager.supportsMultipleUsers()
                 || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)
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 6729f9f..591b1b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -24,6 +24,8 @@
 
 import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -457,8 +459,10 @@
             mNavigationBarWindowState = state;
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
 
+            mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NAV_BAR_HIDDEN,
+                    !isNavBarWindowVisible());
             mNavigationBarView.getRotateSuggestionButton()
-                    .onNavigationBarWindowVisibilityChange(state == WINDOW_STATE_SHOWING);
+                    .onNavigationBarWindowVisibilityChange(isNavBarWindowVisible());
         }
     }
 
@@ -776,44 +780,52 @@
             IActivityTaskManager activityManager = ActivityTaskManager.getService();
             boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
             boolean inLockTaskMode = activityManager.isInLockTaskMode();
-            if (inLockTaskMode && !touchExplorationEnabled) {
-                long time = System.currentTimeMillis();
+            boolean stopLockTaskMode = false;
+            try {
+                if (inLockTaskMode && !touchExplorationEnabled) {
+                    long time = System.currentTimeMillis();
 
-                // If we recently long-pressed the other button then they were
-                // long-pressed 'together'
-                if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
-                    activityManager.stopSystemLockTaskMode();
-                    // When exiting refresh disabled flags.
-                    mNavigationBarView.updateNavButtonIcons();
-                    return true;
-                } else if (v.getId() == btnId1) {
-                    ButtonDispatcher button = btnId2 == R.id.recent_apps
-                            ? mNavigationBarView.getRecentsButton()
-                            : mNavigationBarView.getHomeButton();
-                    if (!button.getCurrentView().isPressed()) {
-                        // If we aren't pressing recents/home right now then they presses
-                        // won't be together, so send the standard long-press action.
+                    // If we recently long-pressed the other button then they were
+                    // long-pressed 'together'
+                    if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
+                        stopLockTaskMode = true;
+                        return true;
+                    } else if (v.getId() == btnId1) {
+                        ButtonDispatcher button = btnId2 == R.id.recent_apps
+                                ? mNavigationBarView.getRecentsButton()
+                                : mNavigationBarView.getHomeButton();
+                        if (!button.getCurrentView().isPressed()) {
+                            // If we aren't pressing recents/home right now then they presses
+                            // won't be together, so send the standard long-press action.
+                            sendBackLongPress = true;
+                        }
+                    }
+                    mLastLockToAppLongPress = time;
+                } else {
+                    // If this is back still need to handle sending the long-press event.
+                    if (v.getId() == btnId1) {
                         sendBackLongPress = true;
+                    } else if (touchExplorationEnabled && inLockTaskMode) {
+                        // When in accessibility mode a long press that is recents/home (not back)
+                        // should stop lock task.
+                        stopLockTaskMode = true;
+                        return true;
+                    } else if (v.getId() == btnId2) {
+                        return btnId2 == R.id.recent_apps
+                                ? onLongPressRecents()
+                                : onHomeLongClick(
+                                        mNavigationBarView.getHomeButton().getCurrentView());
                     }
                 }
-                mLastLockToAppLongPress = time;
-            } else {
-                // If this is back still need to handle sending the long-press event.
-                if (v.getId() == btnId1) {
-                    sendBackLongPress = true;
-                } else if (touchExplorationEnabled && inLockTaskMode) {
-                    // When in accessibility mode a long press that is recents/home (not back)
-                    // should stop lock task.
+            } finally {
+                if (stopLockTaskMode) {
                     activityManager.stopSystemLockTaskMode();
                     // When exiting refresh disabled flags.
                     mNavigationBarView.updateNavButtonIcons();
-                    return true;
-                } else if (v.getId() == btnId2) {
-                    return btnId2 == R.id.recent_apps
-                            ? onLongPressRecents()
-                            : onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView());
+                    mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING, false);
                 }
             }
+
             if (sendBackLongPress) {
                 KeyButtonView keyButtonView = (KeyButtonView) v;
                 keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
@@ -925,6 +937,10 @@
         }
     }
 
+    public boolean isNavBarWindowVisible() {
+        return mNavigationBarWindowState == WINDOW_STATE_SHOWING;
+    }
+
     /**
      * Checks current navigation bar mode and make transitions.
      */
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 e2a63cc..a45d86e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
 
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 
 import android.animation.LayoutTransition;
@@ -34,7 +35,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
@@ -48,8 +48,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
-import android.view.IPinnedStackController;
-import android.view.IPinnedStackListener;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
@@ -237,45 +235,6 @@
         }
     };
 
-    private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
-        @Override
-        public void onListenerRegistered(IPinnedStackController controller) {
-        }
-
-        @Override
-        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-            post(() -> {
-                // TODO remove this and do below when mNavigationIconHints changes
-                if (imeVisible) {
-                    getBackButton().setVisibility(VISIBLE);
-                    reloadNavIcons();
-                } else {
-                    getImeSwitchButton().setVisibility(GONE);
-                }
-                mImeVisible = imeVisible;
-                updateWindowTouchable();
-            });
-        }
-
-        @Override
-        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
-        }
-
-        @Override
-        public void onMinimizedStateChanged(boolean isMinimized) {
-        }
-
-        @Override
-        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
-                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
-                int displayRotation) {
-        }
-
-        @Override
-        public void onActionsChanged(ParceledListSlice actions) {
-        }
-    };
-
     private BroadcastReceiver mOverlaysChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -507,9 +466,7 @@
         final boolean useAltBack =
                 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
         final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-        float degrees = useAltBack
-                ? (isRtl ? 270 : -90)
-                : (isRtl ? 180 : 0);
+        float degrees = useAltBack ? (isRtl ? 90 : -90) : 0;
         if (drawable.getRotation() == degrees) {
             return;
         }
@@ -559,10 +516,13 @@
 
     public void setNavigationIconHints(int hints) {
         if (hints == mNavigationIconHints) return;
-        final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
-        if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
-            mTransitionListener.onBackAltCleared();
+        final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+        final boolean oldBackAlt =
+                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+        if (newBackAlt != oldBackAlt) {
+            onImeVisibilityChanged(newBackAlt);
         }
+
         if (DEBUG) {
             android.widget.Toast.makeText(getContext(),
                 "Navigation icon hints = " + hints,
@@ -572,6 +532,14 @@
         updateNavButtonIcons();
     }
 
+    private void onImeVisibilityChanged(boolean visible) {
+        if (!visible) {
+            mTransitionListener.onBackAltCleared();
+        }
+        mImeVisible = visible;
+        updateWindowTouchable();
+    }
+
     public void setDisabledFlags(int disabledFlags) {
         if (mDisabledFlags == disabledFlags) return;
 
@@ -665,10 +633,6 @@
         return getContext().getDisplay();
     }
 
-    public boolean inScreenPinning() {
-        return ActivityManagerWrapper.getInstance().isScreenPinningActive();
-    }
-
     public void setLayoutTransitionsEnabled(boolean enabled) {
         mLayoutTransitionsEnabled = enabled;
         updateLayoutTransitionsEnabled();
@@ -724,6 +688,8 @@
 
     public void onPanelExpandedChange(boolean expanded) {
         updateSlippery();
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+                expanded);
     }
 
     public void updateStates() {
@@ -743,10 +709,6 @@
                 showSwipeUpUI ? mQuickStepAccessibilityDelegate : null);
     }
 
-    public boolean isNotificationsFullyCollapsed() {
-        return mPanelView.isFullyCollapsed();
-    }
-
     /**
      * Updates the {@link WindowManager.LayoutParams.FLAG_SLIPPERY} state dependent on if swipe up
      * is enabled, or the notifications is fully opened without being in an animated state. If
@@ -1114,14 +1076,6 @@
         filter.addDataScheme("package");
         getContext().registerReceiver(mOverlaysChangedReceiver, filter);
         mEdgeBackGestureHandler.onNavBarAttached();
-
-        if (QuickStepContract.isGesturalMode(getContext())) {
-            try {
-                WindowManagerWrapper.getInstance().addPinnedStackListener(mImeChangedListener);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to register pinned stack listener", e);
-            }
-        }
         updateWindowTouchable();
     }
 
@@ -1139,8 +1093,6 @@
 
         getContext().unregisterReceiver(mOverlaysChangedReceiver);
         mEdgeBackGestureHandler.onNavBarDetached();
-
-        WindowManagerWrapper.getInstance().removePinnedStackListener(mImeChangedListener);
     }
 
     private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
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 0d2fe13..ed79476 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -20,7 +20,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.app.AlarmManager;
-import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
@@ -121,8 +120,7 @@
     private final Handler mHandler;
 
     private final SysuiColorExtractor mColorExtractor;
-    private GradientColors mLockColors;
-    private GradientColors mSystemColors;
+    private GradientColors mColors;
     private boolean mNeedsDrawableColorUpdate;
 
     protected float mScrimBehindAlpha;
@@ -190,10 +188,7 @@
 
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
         mColorExtractor.addOnColorsChangedListener(this);
-        mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
-                ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
-        mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
-                ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
+        mColors = mColorExtractor.getNeutralColors();
         mNeedsDrawableColorUpdate = true;
 
         final ScrimState[] states = ScrimState.values();
@@ -201,7 +196,6 @@
             states[i].init(mScrimInFront, mScrimBehind, mDozeParameters);
             states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
         }
-        mState = ScrimState.UNINITIALIZED;
 
         mScrimBehind.setDefaultFocusHighlightEnabled(false);
         mScrimInFront.setDefaultFocusHighlightEnabled(false);
@@ -488,17 +482,15 @@
         // Make sure we have the right gradients and their opacities will satisfy GAR.
         if (mNeedsDrawableColorUpdate) {
             mNeedsDrawableColorUpdate = false;
-            boolean isKeyguard = mKeyguardUpdateMonitor.isKeyguardVisible() && !mKeyguardOccluded;
-            GradientColors currentScrimColors = isKeyguard ? mLockColors : mSystemColors;
             // Only animate scrim color if the scrim view is actually visible
             boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen;
             boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
-            mScrimInFront.setColors(currentScrimColors, animateScrimInFront);
-            mScrimBehind.setColors(currentScrimColors, animateScrimBehind);
+            mScrimInFront.setColors(mColors, animateScrimInFront);
+            mScrimBehind.setColors(mColors, animateScrimBehind);
 
             // Calculate minimum scrim opacity for white or black text.
-            int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
-            int mainColor = currentScrimColors.getMainColor();
+            int textColor = mColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
+            int mainColor = mColors.getMainColor();
             float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
                     4.5f /* minimumContrast */) / 255f;
             mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
@@ -815,7 +807,7 @@
     }
 
     public int getBackgroundColor() {
-        int color = mLockColors.getMainColor();
+        int color = mColors.getMainColor();
         return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
                 Color.red(color), Color.green(color), Color.blue(color));
     }
@@ -830,18 +822,9 @@
 
     @Override
     public void onColorsChanged(ColorExtractor colorExtractor, int which) {
-        if ((which & WallpaperManager.FLAG_LOCK) != 0) {
-            mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
-                    ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
-            mNeedsDrawableColorUpdate = true;
-            scheduleUpdate();
-        }
-        if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
-            mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
-                    ColorExtractor.TYPE_DARK, mState != ScrimState.UNLOCKED);
-            mNeedsDrawableColorUpdate = true;
-            scheduleUpdate();
-        }
+        mColors = mColorExtractor.getNeutralColors();
+        mNeedsDrawableColorUpdate = true;
+        scheduleUpdate();
     }
 
     @VisibleForTesting
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 b34e24e..aaaf3ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1152,7 +1152,6 @@
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.onDensityOrFontScaleChanged();
         }
-        mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
         // TODO: Bring these out of StatusBar.
         ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
                 .onDensityOrFontScaleChanged();
@@ -3949,6 +3948,7 @@
                 }
 
                 private void setPulsing(boolean pulsing) {
+                    mStatusBarKeyguardViewManager.setPulsing(pulsing);
                     mKeyguardViewMediator.setPulsing(pulsing);
                     mNotificationPanel.setPulsing(pulsing);
                     mVisualStabilityManager.setPulsing(pulsing);
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 92cd280..e3cc3d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -40,14 +40,18 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUIFactory;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 
@@ -61,7 +65,7 @@
  * {@link com.android.keyguard.KeyguardViewBase}.
  */
 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
-        StatusBarStateController.StateListener {
+        StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener {
 
     // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
     private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -105,6 +109,18 @@
             mNotificationPanelView.updateLockIcon();
         }
     };
+    private final DockManager.DockEventListener mDockEventListener =
+            new DockManager.DockEventListener() {
+                @Override
+                public void onEvent(int event) {
+                    boolean isDocked = mDockManager.isDocked();
+            if (isDocked == mIsDocked) {
+                return;
+            }
+            mIsDocked = isDocked;
+            updateStates();
+        }
+    };
 
     protected LockPatternUtils mLockPatternUtils;
     protected ViewMediatorCallback mViewMediatorCallback;
@@ -119,6 +135,9 @@
     protected boolean mOccluded;
     protected boolean mRemoteInputActive;
     private boolean mDozing;
+    private boolean mPulsing;
+    private boolean mGesturalNav;
+    private boolean mIsDocked;
 
     protected boolean mFirstUpdate = true;
     protected boolean mLastShowing;
@@ -127,6 +146,9 @@
     private boolean mLastBouncerDismissible;
     protected boolean mLastRemoteInputActive;
     private boolean mLastDozing;
+    private boolean mLastGesturalNav;
+    private boolean mLastIsDocked;
+    private boolean mLastPulsing;
     private int mLastBiometricMode;
     private boolean mGoingToSleepVisibleNotOccluded;
 
@@ -139,6 +161,7 @@
             (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
     private final NotificationMediaManager mMediaManager =
             Dependency.get(NotificationMediaManager.class);
+    private final DockManager mDockManager;
 
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -159,8 +182,15 @@
         mViewMediatorCallback = callback;
         mLockPatternUtils = lockPatternUtils;
         mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+        mGesturalNav = QuickStepContract.isGesturalMode(context);
         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
         Dependency.get(StatusBarStateController.class).addCallback(this);
+        Dependency.get(ConfigurationController.class).addCallback(this);
+        mDockManager = SysUiServiceProvider.getComponent(context, DockManager.class);
+        if (mDockManager != null) {
+            mDockManager.addListener(mDockEventListener);
+            mIsDocked = mDockManager.isDocked();
+        }
     }
 
     public void registerStatusBar(StatusBar statusBar,
@@ -241,6 +271,9 @@
     }
 
     private void hideBouncer(boolean destroyView) {
+        if (mBouncer == null) {
+            return;
+        }
         mBouncer.hide(destroyView);
         cancelPendingWakeupAction();
     }
@@ -354,6 +387,16 @@
         }
     }
 
+    /**
+     * If {@link StatusBar} is pulsing.
+     */
+    public void setPulsing(boolean pulsing) {
+        if (mPulsing != pulsing) {
+            mPulsing = pulsing;
+            updateStates();
+        }
+    }
+
     public void setNeedsInput(boolean needsInput) {
         mStatusBarWindowController.setKeyguardNeedsInput(needsInput);
     }
@@ -492,10 +535,20 @@
             StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
     }
 
+    @Override
     public void onDensityOrFontScaleChanged() {
         hideBouncer(true /* destroyView */);
     }
 
+    @Override
+    public void onOverlayChanged() {
+        boolean gesturalNav = QuickStepContract.isGesturalMode(mContext);
+        if (gesturalNav != mGesturalNav) {
+            mGesturalNav = gesturalNav;
+            updateStates();
+        }
+    }
+
     public void onThemeChanged() {
         hideBouncer(true /* destroyView */);
         mBouncer.prepare();
@@ -643,7 +696,10 @@
         mLastBouncerDismissible = bouncerDismissible;
         mLastRemoteInputActive = remoteInputActive;
         mLastDozing = mDozing;
+        mLastPulsing = mPulsing;
         mLastBiometricMode = mBiometricUnlockController.getMode();
+        mLastGesturalNav = mGesturalNav;
+        mLastIsDocked = mIsDocked;
         mStatusBar.onKeyguardViewManagerStatesUpdated();
     }
 
@@ -671,8 +727,10 @@
         int biometricMode = mBiometricUnlockController.getMode();
         boolean keyguardShowing = mShowing && !mOccluded;
         boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
+        boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked)
+                && mGesturalNav;
         return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
-                || mRemoteInputActive);
+                || mRemoteInputActive || keyguardWithGestureNav);
     }
 
     /**
@@ -681,8 +739,10 @@
     protected boolean getLastNavBarVisible() {
         boolean keyguardShowing = mLastShowing && !mLastOccluded;
         boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
+        boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing
+                || mLastPulsing && !mLastIsDocked) && mLastGesturalNav;
         return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
-                || mLastRemoteInputActive);
+                || mLastRemoteInputActive || keyguardWithGestureNav);
     }
 
     public boolean shouldDismissOnMenuPressed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index 03c89c6..dd0c344 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -37,6 +37,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.FloatProperty;
 import android.view.ContextThemeWrapper;
+import android.view.View;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
@@ -79,9 +80,10 @@
     private final ShadowDrawableState mState;
     private AnimatedVectorDrawable mAnimatedDrawable;
 
-    public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor) {
+    public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
+            boolean horizontalFlip) {
         this(d, new ShadowDrawableState(lightColor, darkColor,
-                d instanceof AnimatedVectorDrawable));
+                d instanceof AnimatedVectorDrawable, horizontalFlip));
     }
 
     private KeyButtonDrawable(Drawable d, ShadowDrawableState state) {
@@ -282,7 +284,12 @@
         // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared.
         final Drawable d = mState.mChildState.newDrawable().mutate();
         setDrawableBounds(d);
+        canvas.save();
+        if (mState.mHorizontalFlip) {
+            canvas.scale(-1f, 1f, width * 0.5f, height * 0.5f);
+        }
         d.draw(canvas);
+        canvas.restore();
 
         if (mState.mIsHardwareBitmap) {
             bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false);
@@ -305,7 +312,12 @@
         // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared.
         final Drawable d = mState.mChildState.newDrawable().mutate();
         setDrawableBounds(d);
+        canvas.save();
+        if (mState.mHorizontalFlip) {
+            canvas.scale(-1f, 1f, width * 0.5f, height * 0.5f);
+        }
         d.draw(canvas);
+        canvas.restore();
 
         // Draws the shadow from original drawable
         Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
@@ -357,6 +369,7 @@
         int mShadowColor;
         float mDarkIntensity;
         int mAlpha;
+        boolean mHorizontalFlip;
 
         boolean mIsHardwareBitmap;
         Bitmap mLastDrawnIcon;
@@ -368,11 +381,12 @@
         final boolean mSupportsAnimation;
 
         public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor,
-                boolean animated) {
+                boolean animated, boolean horizontalFlip) {
             mLightColor = lightColor;
             mDarkColor = darkColor;
             mSupportsAnimation = animated;
             mAlpha = 255;
+            mHorizontalFlip = horizontalFlip;
         }
 
         @Override
@@ -400,7 +414,7 @@
      * @return KeyButtonDrawable
      */
     public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon,
-        boolean hasShadow) {
+            boolean hasShadow) {
         final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
         final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
         Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
@@ -409,7 +423,7 @@
     }
 
     public static KeyButtonDrawable create(Context lightContext, Context darkContext,
-        @DrawableRes int iconResId, boolean hasShadow) {
+            @DrawableRes int iconResId, boolean hasShadow) {
         return create(lightContext,
             Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor),
             Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor),
@@ -418,10 +432,12 @@
 
     public static KeyButtonDrawable create(Context context, @ColorInt int lightColor,
         @ColorInt int darkColor, @DrawableRes int iconResId, boolean hasShadow) {
-        final KeyButtonDrawable drawable = new KeyButtonDrawable(context.getDrawable(iconResId),
-            lightColor, darkColor);
+        final Resources res = context.getResources();
+        boolean isRtl = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+        Drawable d = context.getDrawable(iconResId);
+        final KeyButtonDrawable drawable = new KeyButtonDrawable(d, lightColor, darkColor,
+                isRtl && d.isAutoMirrored());
         if (hasShadow) {
-            final Resources res = context.getResources();
             int offsetX = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_x);
             int offsetY = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_y);
             int radius = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_radius);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index c5996a1..11e5625 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -47,6 +47,8 @@
 import java.io.PrintWriter;
 import java.util.BitSet;
 import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 
 public class MobileSignalController extends SignalController<
@@ -73,6 +75,10 @@
     private SignalStrength mSignalStrength;
     private MobileIconGroup mDefaultIcons;
     private Config mConfig;
+    @VisibleForTesting
+    boolean mInflateSignalStrengths = false;
+    // Some specific carriers have 5GE network which is special LTE CA network.
+    private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
 
     // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
     // need listener lists anymore.
@@ -114,6 +120,7 @@
 
     public void setConfiguration(Config config) {
         mConfig = config;
+        updateInflateSignalStrength();
         mapIconSets();
         updateTelephony();
     }
@@ -236,11 +243,19 @@
                         TelephonyIcons.LTE_PLUS);
             }
         }
+        mNetworkToIconLookup.put(NETWORK_TYPE_LTE_CA_5GE,
+                TelephonyIcons.LTE_CA_5G_E);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
     }
 
+    private void updateInflateSignalStrength() {
+        mInflateSignalStrengths = SubscriptionManager.getResourcesForSubId(mContext,
+               mSubscriptionInfo.getSubscriptionId())
+               .getBoolean(R.bool.config_inflateSignalStrength);
+    }
+
     private int getNumLevels() {
-        if (mConfig.inflateSignalStrengths) {
+        if (mInflateSignalStrengths) {
             return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1;
         }
         return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
@@ -252,7 +267,7 @@
             return SignalDrawable.getCarrierChangeState(getNumLevels());
         } else if (mCurrentState.connected) {
             int level = mCurrentState.level;
-            if (mConfig.inflateSignalStrengths) {
+            if (mInflateSignalStrengths) {
                 level++;
             }
             boolean dataDisabled = mCurrentState.userSetup
@@ -381,6 +396,26 @@
         }
     }
 
+    private boolean isCarrierSpecificDataIcon() {
+        if (mConfig.patternOfCarrierSpecificDataIcon == null
+                || mConfig.patternOfCarrierSpecificDataIcon.length() == 0) {
+            return false;
+        }
+
+        Pattern stringPattern = Pattern.compile(mConfig.patternOfCarrierSpecificDataIcon);
+        String[] operatorNames = new String[]{mServiceState.getOperatorAlphaLongRaw(),
+                mServiceState.getOperatorAlphaShortRaw()};
+        for (String opName : operatorNames) {
+            if (!TextUtils.isEmpty(opName)) {
+                Matcher matcher = stringPattern.matcher(opName);
+                if (matcher.find()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Updates the network's name based on incoming spn and plmn.
      */
@@ -535,6 +570,7 @@
         pw.println("  mSignalStrength=" + mSignalStrength + ",");
         pw.println("  mDataState=" + mDataState + ",");
         pw.println("  mDataNetType=" + mDataNetType + ",");
+        pw.println("  mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
     }
 
     class MobilePhoneStateListener extends PhoneStateListener {
@@ -559,12 +595,8 @@
                         + " dataState=" + state.getDataRegState());
             }
             mServiceState = state;
-            if (state != null) {
-                mDataNetType = state.getDataNetworkType();
-                if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
-                        mServiceState.isUsingCarrierAggregation()) {
-                    mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
-                }
+            if (mServiceState != null) {
+                updateDataNetType(mServiceState.getDataNetworkType());
             }
             updateTelephony();
         }
@@ -576,14 +608,21 @@
                         + " type=" + networkType);
             }
             mDataState = state;
-            mDataNetType = networkType;
-            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
-                    mServiceState.isUsingCarrierAggregation()) {
-                mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
-            }
+            updateDataNetType(networkType);
             updateTelephony();
         }
 
+        private void updateDataNetType(int networkType) {
+            mDataNetType = networkType;
+            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) {
+                if (isCarrierSpecificDataIcon()) {
+                    mDataNetType = NETWORK_TYPE_LTE_CA_5GE;
+                } else if (mServiceState != null && mServiceState.isUsingCarrierAggregation()) {
+                    mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
+                }
+            }
+        }
+
         @Override
         public void onDataActivity(int direction) {
             if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d01430a..faf63c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -55,6 +55,7 @@
 import android.util.MathUtils;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
@@ -108,16 +109,10 @@
     private final SubscriptionDefaults mSubDefaults;
     private final DataSaverController mDataSaverController;
     private final CurrentUserTracker mUserTracker;
+    private final Object mLock = new Object();
     private Config mConfig;
 
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onActiveDataSubscriptionIdChanged(int subId) {
-            mActiveMobileDataSubscription = subId;
-            doUpdateMobileControllers();
-        }
-    };
-
+    private PhoneStateListener mPhoneStateListener;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
     // Subcontrollers.
@@ -279,6 +274,14 @@
         // TODO: Move off of the deprecated CONNECTIVITY_ACTION broadcast and rely on callbacks
         // exclusively for status bar icons.
         mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler);
+        // Register the listener on our bg looper
+        mPhoneStateListener = new PhoneStateListener(bgLooper) {
+            @Override
+            public void onActiveDataSubscriptionIdChanged(int subId) {
+                mActiveMobileDataSubscription = subId;
+                doUpdateMobileControllers();
+            }
+        };
     }
 
     public DataSaverController getDataSaverController() {
@@ -600,7 +603,9 @@
             updateNoSims();
             return;
         }
-        setCurrentSubscriptions(subscriptions);
+        synchronized (mLock) {
+            setCurrentSubscriptionsLocked(subscriptions);
+        }
         updateNoSims();
         recalculateEmergency();
     }
@@ -628,8 +633,9 @@
         return false;
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
-    void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) {
+    public void setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions) {
         Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
             @Override
             public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
@@ -1102,6 +1108,7 @@
         boolean hspaDataDistinguishable;
         boolean inflateSignalStrengths = false;
         boolean alwaysShowDataRatIcon = false;
+        public String patternOfCarrierSpecificDataIcon = "";
 
         /**
          * Mapping from NR 5G status string to an integer. The NR 5G status string should match
@@ -1140,6 +1147,8 @@
                         CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
                 config.hideLtePlus = b.getBoolean(
                         CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
+                config.patternOfCarrierSpecificDataIcon = b.getString(
+                        CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING);
                 String nr5GIconConfiguration =
                         b.getString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING);
                 if (!TextUtils.isEmpty(nr5GIconConfiguration)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index e151ca3..c22ff8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -35,6 +35,7 @@
     static final int ICON_3G = R.drawable.ic_3g_mobiledata;
     static final int ICON_4G = R.drawable.ic_4g_mobiledata;
     static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata;
+    static final int ICON_5G_E = R.drawable.ic_5g_e_mobiledata;
     static final int ICON_1X = R.drawable.ic_1x_mobiledata;
     static final int ICON_5G = R.drawable.ic_5g_mobiledata;
     static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata;
@@ -204,6 +205,19 @@
             TelephonyIcons.ICON_LTE_PLUS,
             true);
 
+    static final MobileIconGroup LTE_CA_5G_E = new MobileIconGroup(
+            "5Ge",
+            null,
+            null,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            0,
+            0,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.data_connection_5ge,
+            TelephonyIcons.ICON_5G_E,
+            true);
+
     static final MobileIconGroup NR_5G = new MobileIconGroup(
             "5G",
             null,
@@ -276,6 +290,7 @@
         ICON_NAME_TO_ICON.put("h+", H_PLUS);
         ICON_NAME_TO_ICON.put("4g", FOUR_G);
         ICON_NAME_TO_ICON.put("4g+", FOUR_G_PLUS);
+        ICON_NAME_TO_ICON.put("5ge", LTE_CA_5G_E);
         ICON_NAME_TO_ICON.put("lte", LTE);
         ICON_NAME_TO_ICON.put("lte+", LTE_PLUS);
         ICON_NAME_TO_ICON.put("5g", NR_5G);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
new file mode 100644
index 0000000..f318f8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -0,0 +1,123 @@
+/*
+ * 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.theme;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.om.OverlayManager;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import com.google.android.collect.Sets;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Controls the application of theme overlays across the system for all users.
+ * This service is responsible for:
+ * - Observing changes to Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES and applying the
+ * corresponding overlays across the system
+ * - Observing user switches, applying the overlays for the current user to user 0 (for systemui)
+ * - Observing work profile changes and applying overlays from the primary user to their
+ * associated work profiles
+ */
+public class ThemeOverlayController extends SystemUI {
+    private static final String TAG = "ThemeOverlayController";
+    private static final boolean DEBUG = false;
+
+    private ThemeOverlayManager mThemeManager;
+    private UserManager mUserManager;
+
+    @Override
+    public void start() {
+        if (DEBUG) Log.d(TAG, "Start");
+        mUserManager = mContext.getSystemService(UserManager.class);
+        mThemeManager = new ThemeOverlayManager(
+                mContext.getSystemService(OverlayManager.class),
+                mContext.getString(R.string.launcher_overlayable_package));
+        final Handler bgHandler = Dependency.get(Dependency.BG_HANDLER);
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
+                updateThemeOverlays();
+            }
+        }, UserHandle.ALL, filter, null, bgHandler);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
+                false,
+                new ContentObserver(bgHandler) {
+                    @Override
+                    public void onChange(boolean selfChange, Uri uri, int userId) {
+                        if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
+                        if (ActivityManager.getCurrentUser() == userId) {
+                            updateThemeOverlays();
+                        }
+                    }
+                },
+                UserHandle.USER_ALL);
+    }
+
+    private void updateThemeOverlays() {
+        final int currentUser = ActivityManager.getCurrentUser();
+        final String overlayPackageJson = Settings.Secure.getStringForUser(
+                mContext.getContentResolver(), Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
+                currentUser);
+        if (DEBUG) Log.d(TAG, "updateThemeOverlays: " + overlayPackageJson);
+        final Map<String, String> categoryToPackage = new ArrayMap<>();
+        if (!TextUtils.isEmpty(overlayPackageJson)) {
+            try {
+                JSONObject object = new JSONObject(overlayPackageJson);
+                for (String category : ThemeOverlayManager.THEME_CATEGORIES) {
+                    if (object.has(category)) {
+                        categoryToPackage.put(category, object.getString(category));
+                    }
+                }
+            } catch (JSONException e) {
+                Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
+            }
+        }
+        Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
+        for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
+            if (userInfo.isManagedProfile()) {
+                userHandles.add(userInfo.getUserHandle());
+            }
+        }
+        mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
new file mode 100644
index 0000000..1a9fd53
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
@@ -0,0 +1,161 @@
+/*
+ * 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.theme;
+
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.google.android.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+class ThemeOverlayManager {
+    private static final String TAG = "ThemeOverlayManager";
+    private static final boolean DEBUG = false;
+
+    @VisibleForTesting
+    static final String ANDROID_PACKAGE = "android";
+    @VisibleForTesting
+    static final String SETTINGS_PACKAGE = "com.android.settings";
+    @VisibleForTesting
+    static final String SYSUI_PACKAGE = "com.android.systemui";
+
+    @VisibleForTesting
+    static final String OVERLAY_CATEGORY_COLOR = "android.theme.customization.accent_color";
+    @VisibleForTesting
+    static final String OVERLAY_CATEGORY_FONT = "android.theme.customization.font";
+    @VisibleForTesting
+    static final String OVERLAY_CATEGORY_SHAPE =
+            "android.theme.customization.adaptive_icon_shape";
+    @VisibleForTesting
+    static final String OVERLAY_CATEGORY_ICON_ANDROID =
+            "android.theme.customization.icon_pack.android";
+    @VisibleForTesting
+    static final String OVERLAY_CATEGORY_ICON_SYSUI =
+            "android.theme.customization.icon_pack.systemui";
+    @VisibleForTesting
+    static final String OVERLAY_CATEGORY_ICON_SETTINGS =
+            "android.theme.customization.icon_pack.settings";
+    @VisibleForTesting
+    static final String OVERLAY_CATEGORY_ICON_LAUNCHER =
+            "android.theme.customization.icon_pack.launcher";
+
+    /* All theme customization categories used by the system. */
+    static final Set<String> THEME_CATEGORIES = Sets.newHashSet(
+            OVERLAY_CATEGORY_COLOR,
+            OVERLAY_CATEGORY_FONT,
+            OVERLAY_CATEGORY_SHAPE,
+            OVERLAY_CATEGORY_ICON_ANDROID,
+            OVERLAY_CATEGORY_ICON_SYSUI,
+            OVERLAY_CATEGORY_ICON_SETTINGS,
+            OVERLAY_CATEGORY_ICON_LAUNCHER);
+
+    /* Categories that need to applied to the current user as well as the system user. */
+    @VisibleForTesting
+    static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet(
+            OVERLAY_CATEGORY_COLOR,
+            OVERLAY_CATEGORY_FONT,
+            OVERLAY_CATEGORY_SHAPE,
+            OVERLAY_CATEGORY_ICON_ANDROID,
+            OVERLAY_CATEGORY_ICON_SYSUI);
+
+    /* Allowed overlay categories for each target package. */
+    private final Map<String, Set<String>> mTargetPackageToCategories = new ArrayMap<>();
+    /* Target package for each overlay category. */
+    private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>();
+    private final OverlayManager mOverlayManager;
+    private final String mLauncherPackage;
+
+    ThemeOverlayManager(OverlayManager overlayManager, String launcherPackage) {
+        mOverlayManager = overlayManager;
+        mLauncherPackage = launcherPackage;
+        mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
+                OVERLAY_CATEGORY_COLOR, OVERLAY_CATEGORY_FONT,
+                OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
+        mTargetPackageToCategories.put(SYSUI_PACKAGE,
+                Sets.newHashSet(OVERLAY_CATEGORY_ICON_SYSUI));
+        mTargetPackageToCategories.put(SETTINGS_PACKAGE,
+                Sets.newHashSet(OVERLAY_CATEGORY_ICON_SETTINGS));
+        mTargetPackageToCategories.put(mLauncherPackage,
+                Sets.newHashSet(OVERLAY_CATEGORY_ICON_LAUNCHER));
+        mCategoryToTargetPackage.put(OVERLAY_CATEGORY_COLOR, ANDROID_PACKAGE);
+        mCategoryToTargetPackage.put(OVERLAY_CATEGORY_FONT, ANDROID_PACKAGE);
+        mCategoryToTargetPackage.put(OVERLAY_CATEGORY_SHAPE, ANDROID_PACKAGE);
+        mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE);
+        mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SYSUI, SYSUI_PACKAGE);
+        mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SETTINGS, SETTINGS_PACKAGE);
+        mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_LAUNCHER, mLauncherPackage);
+    }
+
+    /**
+     * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that
+     * affect sysui will also be applied to the system user.
+     */
+    void applyCurrentUserOverlays(
+            Map<String, String> categoryToPackage, Set<UserHandle> userHandles) {
+        final Map<Boolean, List<String>> categorySplit = THEME_CATEGORIES.stream().collect(
+                Collectors.partitioningBy((category) -> categoryToPackage.containsKey(category)));
+        final List<String> overlayCategoriesToEnable = categorySplit.get(true);
+        final List<String> overlayCategoriesToDisable = categorySplit.get(false);
+
+        // Disable all overlays that have not been specified in the user setting.
+        final List<OverlayInfo> overlays = new ArrayList<>();
+        overlayCategoriesToDisable.stream()
+                .map(category -> mCategoryToTargetPackage.get(category))
+                .collect(Collectors.toSet())
+                .forEach(targetPackage -> overlays.addAll(mOverlayManager
+                        .getOverlayInfosForTarget(targetPackage, UserHandle.SYSTEM)));
+        overlays.stream()
+                .filter(o ->
+                        mTargetPackageToCategories.get(o.targetPackageName).contains(o.category))
+                .filter(o -> overlayCategoriesToDisable.contains(o.category))
+                .filter(o -> o.isEnabled())
+                .forEach(o -> setEnabled(o.packageName, o.category, userHandles, false));
+
+
+        // Enable all overlays specified in the user setting.
+        overlayCategoriesToEnable.forEach((category) ->
+                setEnabled(categoryToPackage.get(category), category, userHandles, true));
+    }
+
+    private void setEnabled(
+            String packageName, String category, Set<UserHandle> handles, boolean enabled) {
+        for (UserHandle userHandle : handles) {
+            setEnabled(packageName, userHandle, enabled);
+        }
+        if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) {
+            setEnabled(packageName, UserHandle.SYSTEM, enabled);
+        }
+    }
+
+    private void setEnabled(String pkg, UserHandle userHandle, boolean enabled) {
+        if (DEBUG) Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled));
+        if (enabled) {
+            mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle);
+        } else {
+            mOverlayManager.setEnabled(pkg, false, userHandle);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 2a84c5d..9bbfd22 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -94,7 +94,6 @@
     public static final int DISMISS_STREAM_GONE = 7;
     public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
     public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9;
-    public static final int DISMISS_REASON_ODI_CAPTIONS_CLICKED = 10;
     public static final String[] DISMISS_REASONS = {
             "unknown",
             "touch_outside",
@@ -105,8 +104,7 @@
             "done_clicked",
             "a11y_stream_changed",
             "output_chooser",
-            "usb_temperature_below_threshold",
-            "odi_captions_clicked"
+            "usb_temperature_below_threshold"
     };
 
     public static final int SHOW_REASON_UNKNOWN = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 2094b36..5095370 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -30,7 +30,6 @@
 import static android.view.View.VISIBLE;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
-import static com.android.systemui.volume.Events.DISMISS_REASON_ODI_CAPTIONS_CLICKED;
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
 
 import android.animation.ObjectAnimator;
@@ -519,7 +518,6 @@
             mODICaptionsIcon.setOnConfirmedTapListener(() -> {
                 onCaptionIconClicked();
                 Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_CLICK);
-                dismissH(DISMISS_REASON_ODI_CAPTIONS_CLICKED);
             }, mHandler);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index f2ad958..17fbe09 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -18,12 +18,14 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
 import android.database.ContentObserver;
+import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -52,6 +54,8 @@
 
     private static final String BUBBLE_CLOCK = BubbleClockController.class.getName();
     private static final Class<?> BUBBLE_CLOCK_CLASS = BubbleClockController.class;
+    private static final int USER_ID = 0;
+    private static final Uri SETTINGS_URI = null;
 
     private ClockManager mClockManager;
     private ContentObserver mContentObserver;
@@ -106,10 +110,10 @@
     @Test
     public void getCurrentClock_default() {
         // GIVEN that settings doesn't contain any values
-        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(null);
-        when(mMockSettingsWrapper.getDockedClockFace()).thenReturn(null);
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(null);
+        when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(null);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false);
+        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
         // THEN the result is null, indicated the default clock face should be used.
         assertThat(mClockManager.getCurrentClock()).isNull();
     }
@@ -117,9 +121,9 @@
     @Test
     public void getCurrentClock_customClock() {
         // GIVEN that settings is set to the bubble clock face
-        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false);
+        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
         // THEN the plugin is the bubble clock face.
         assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
     }
@@ -127,9 +131,9 @@
     @Test
     public void onClockChanged_customClock() {
         // GIVEN that settings is set to the bubble clock face
-        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false);
+        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
         // THEN the plugin is the bubble clock face.
         ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
         verify(mMockListener1).onClockChanged(captor.capture());
@@ -139,9 +143,9 @@
     @Test
     public void onClockChanged_uniqueInstances() {
         // GIVEN that settings is set to the bubble clock face
-        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false);
+        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
         // THEN the listeners receive separate instances of the Bubble clock plugin.
         ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
         ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
@@ -156,9 +160,9 @@
     public void getCurrentClock_badSettingsValue() {
         // GIVEN that settings contains a value that doesn't correspond to a
         // custom clock face.
-        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn("bad value");
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn("bad value");
         // WHEN settings change event is fired
-        mContentObserver.onChange(false);
+        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
         // THEN the result is null.
         assertThat(mClockManager.getCurrentClock()).isNull();
     }
@@ -174,7 +178,7 @@
     @Test
     public void getCurrentClock_dockedCustomClock() {
         // GIVEN settings is set to the bubble clock face
-        when(mMockSettingsWrapper.getDockedClockFace()).thenReturn(BUBBLE_CLOCK);
+        when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN dock event fires
         mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
         // THEN the plugin is the bubble clock face.
@@ -184,7 +188,7 @@
     @Test
     public void getCurrentClock_badDockedSettingsValue() {
         // GIVEN settings contains a value that doesn't correspond to an available clock face.
-        when(mMockSettingsWrapper.getDockedClockFace()).thenReturn("bad value");
+        when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn("bad value");
         // WHEN dock event fires
         mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
         // THEN the result is null.
@@ -195,8 +199,8 @@
     public void getCurrentClock_badDockedSettingsFallback() {
         // GIVEN settings contains a value that doesn't correspond to an available clock face, but
         // locked screen settings is set to bubble clock.
-        when(mMockSettingsWrapper.getDockedClockFace()).thenReturn("bad value");
-        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+        when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn("bad value");
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN dock event is fired
         mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
         // THEN the plugin is the bubble clock face.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index 1649f98..67df60a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -18,6 +18,11 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
@@ -27,7 +32,9 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.colorextraction.types.Tonal;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,7 +64,7 @@
         simulateEvent(extractor);
         extractor.setWallpaperVisible(false);
 
-        ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
+        ColorExtractor.GradientColors fallbackColors = extractor.getNeutralColors();
 
         for (int type : sTypes) {
             assertEquals("Not using fallback!",
@@ -96,7 +103,7 @@
         extractor.setWallpaperVisible(true);
         extractor.setHasBackdrop(true);
 
-        ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
+        ColorExtractor.GradientColors fallbackColors = extractor.getNeutralColors();
 
         for (int type : sTypes) {
             assertEquals("Not using fallback!",
@@ -106,6 +113,19 @@
         }
     }
 
+    @Test
+    public void onUiModeChanged_reloadsColors() {
+        Tonal tonal = mock(Tonal.class);
+        ConfigurationController configurationController = mock(ConfigurationController.class);
+        SysuiColorExtractor sysuiColorExtractor = new SysuiColorExtractor(getContext(),
+                tonal, configurationController, false /* registerVisibility */);
+        verify(configurationController).addCallback(eq(sysuiColorExtractor));
+
+        reset(tonal);
+        sysuiColorExtractor.onUiModeChanged();
+        verify(tonal).applyFallback(any(), any());
+    }
+
     private SysuiColorExtractor getTestableExtractor(ColorExtractor.GradientColors colors) {
         return new SysuiColorExtractor(getContext(),
                 (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
@@ -113,7 +133,7 @@
                     outGradientColorsNormal.set(colors);
                     outGradientColorsDark.set(colors);
                     outGradientColorsExtraDark.set(colors);
-                }, false);
+                }, mock(ConfigurationController.class), false);
     }
 
     private void simulateEvent(SysuiColorExtractor extractor) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
index 2020d4b..87a7757 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
@@ -30,7 +30,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
@@ -70,12 +70,10 @@
 
     @Test
     public void testCreation_initialColor() {
-        GradientDrawable drawable = (GradientDrawable) mView.getDrawable();
+        ScrimDrawable drawable = (ScrimDrawable) mView.getDrawable();
         ColorExtractor.GradientColors colors = mView.getColors();
         assertEquals("Main color should be set upon creation",
                 drawable.getMainColor(), colors.getMainColor());
-        assertEquals("Secondary color should be set upon creation",
-                drawable.getSecondaryColor(), colors.getSecondaryColor());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 057f752..d2d294b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -71,6 +72,8 @@
     private UnlockMethodCache mUnlockMethodCache;
     @Mock
     private TunerService mTunerService;
+    @Mock
+    private Handler mHandler;
     private BiometricUnlockController mBiometricUnlockController;
 
     @Before
@@ -172,12 +175,24 @@
         verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
     }
 
+    @Test
+    public void onFinishedGoingToSleep_authenticatesWhenPending() {
+        when(mUpdateMonitor.isGoingToSleep()).thenReturn(true);
+        mBiometricUnlockController.onFinishedGoingToSleep(-1);
+        verify(mHandler, never()).post(any());
+
+        mBiometricUnlockController.onBiometricAuthenticated(1 /* userId */,
+                BiometricSourceType.FACE);
+        mBiometricUnlockController.onFinishedGoingToSleep(-1);
+        verify(mHandler).post(any());
+    }
+
     private class TestableBiometricUnlockController extends BiometricUnlockController {
 
         TestableBiometricUnlockController(boolean faceDismissesKeyguard) {
             super(mContext, mDozeScrimController,
                     mKeyguardViewMediator, mScrimController, mStatusBar, mUnlockMethodCache,
-                    new Handler(), mUpdateMonitor, mTunerService, 0 /* wakeUpDelay */,
+                    mHandler, mUpdateMonitor, mTunerService, 0 /* wakeUpDelay */,
                     faceDismissesKeyguard);
             mFaceDismissesKeyguard = faceDismissesKeyguard;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
index e3c081e..c837c9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
@@ -179,8 +179,10 @@
         final int unusedColor = 0;
         final Drawable d = mock(Drawable.class);
         final ContextualButton button = spy(mBtn0);
-        final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
-        final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
+        final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor,
+                false /* horizontalFlip */));
+        final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor,
+                false /* horizontalFlip */));
         kbd1.setDarkIntensity(TEST_DARK_INTENSITY);
         kbd2.setDarkIntensity(0f);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 4fe18b4..ce5bfce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -428,8 +428,12 @@
 
         IconState iconState = iconArg.getValue();
 
-        int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
-                cutOut);
+        int numSignalStrengthBins = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+        if (mMobileSignalController.mInflateSignalStrengths) {
+            numSignalStrengthBins++;
+            icon++;
+        }
+        int state = SignalDrawable.getState(icon, numSignalStrengthBins, cutOut);
         assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
         assertEquals("Signal icon in status bar", state, iconState.icon);
         assertEquals("Visibility in status bar", visible, iconState.visible);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index ac6544e..0b53c48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -300,7 +300,7 @@
         // We can only test whether unregister gets called if it thinks its in a listening
         // state.
         mNetworkController.mListening = true;
-        mNetworkController.setCurrentSubscriptions(subscriptions);
+        mNetworkController.setCurrentSubscriptionsLocked(subscriptions);
 
         for (int i = 0; i < testSubscriptions.length; i++) {
             if (i == indexToSkipController) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java
new file mode 100644
index 0000000..da039a4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.theme;
+
+import static com.android.systemui.theme.ThemeOverlayManager.ANDROID_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_COLOR;
+import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_FONT;
+import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_ANDROID;
+import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_LAUNCHER;
+import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SETTINGS;
+import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SYSUI;
+import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_SHAPE;
+import static com.android.systemui.theme.ThemeOverlayManager.SETTINGS_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayManager.SYSTEM_USER_CATEGORIES;
+import static com.android.systemui.theme.ThemeOverlayManager.SYSUI_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayManager.THEME_CATEGORIES;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.os.UserHandle;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import com.google.android.collect.Maps;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ThemeOverlayManagerTest extends SysuiTestCase {
+    private static final String TEST_DISABLED_PREFIX = "com.example.";
+    private static final String TEST_ENABLED_PREFIX = "com.example.enabled.";
+
+    private static final Map<String, String> ALL_CATEGORIES_MAP = Maps.newArrayMap();
+
+    static {
+        for (String category : THEME_CATEGORIES) {
+            ALL_CATEGORIES_MAP.put(category, TEST_DISABLED_PREFIX + category);
+        }
+    }
+
+    private static final String LAUNCHER_PACKAGE = "com.android.launcher3";
+    private static final UserHandle TEST_USER = UserHandle.of(5);
+    private static final Set<UserHandle> TEST_USER_HANDLES = Sets.newHashSet(TEST_USER);
+
+    @Mock
+    OverlayManager mOverlayManager;
+
+    private ThemeOverlayManager mManager;
+
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mManager = new ThemeOverlayManager(mOverlayManager, LAUNCHER_PACKAGE);
+        when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM))
+                .thenReturn(Lists.newArrayList(
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_COLOR,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, false),
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_FONT,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, false),
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, false),
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, false),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_COLOR,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, true),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_FONT,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, true),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, true),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, true)));
+        when(mOverlayManager.getOverlayInfosForTarget(SYSUI_PACKAGE, UserHandle.SYSTEM))
+                .thenReturn(Lists.newArrayList(
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_SYSUI,
+                                SYSUI_PACKAGE, OVERLAY_CATEGORY_ICON_SYSUI, false),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SYSUI,
+                                SYSUI_PACKAGE, OVERLAY_CATEGORY_ICON_SYSUI, true)));
+        when(mOverlayManager.getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM))
+                .thenReturn(Lists.newArrayList(
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS,
+                                SETTINGS_PACKAGE, OVERLAY_CATEGORY_ICON_SETTINGS, false),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS,
+                                SETTINGS_PACKAGE, OVERLAY_CATEGORY_ICON_SETTINGS, true)));
+        when(mOverlayManager.getOverlayInfosForTarget(LAUNCHER_PACKAGE, UserHandle.SYSTEM))
+                .thenReturn(Lists.newArrayList(
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_LAUNCHER,
+                                LAUNCHER_PACKAGE, OVERLAY_CATEGORY_ICON_LAUNCHER, false),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_LAUNCHER,
+                                LAUNCHER_PACKAGE, OVERLAY_CATEGORY_ICON_LAUNCHER, true)));
+    }
+
+    @Test
+    public void allCategoriesSpecified_allEnabledExclusively() {
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
+
+        for (String overlayPackage : ALL_CATEGORIES_MAP.values()) {
+            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER);
+        }
+    }
+
+    @Test
+    public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
+
+        for (Map.Entry<String, String> entry : ALL_CATEGORIES_MAP.entrySet()) {
+            if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
+                verify(mOverlayManager).setEnabledExclusiveInCategory(
+                        entry.getValue(), UserHandle.SYSTEM);
+            } else {
+                verify(mOverlayManager, never()).setEnabledExclusiveInCategory(
+                        entry.getValue(), UserHandle.SYSTEM);
+            }
+        }
+    }
+
+    @Test
+    public void allCategoriesSpecified_enabledForAllUserHandles() {
+        Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
+        UserHandle newUserHandle = UserHandle.of(10);
+        userHandles.add(newUserHandle);
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, userHandles);
+
+        for (String overlayPackage : ALL_CATEGORIES_MAP.values()) {
+            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER);
+            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, newUserHandle);
+        }
+    }
+
+    @Test
+    public void allCategoriesSpecified_overlayManagerNotQueried() {
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
+
+        verify(mOverlayManager, never())
+                .getOverlayInfosForTarget(anyString(), any(UserHandle.class));
+    }
+
+    @Test
+    public void someCategoriesSpecified_specifiedEnabled_unspecifiedDisabled() {
+        Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
+        categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
+        categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID);
+
+        mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);
+
+        for (String overlayPackage : categoryToPackage.values()) {
+            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER);
+        }
+        verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS,
+                false, TEST_USER);
+        verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID,
+                false, TEST_USER);
+    }
+
+    @Test
+    public void zeroCategoriesSpecified_allDisabled() {
+        mManager.applyCurrentUserOverlays(Maps.newArrayMap(), TEST_USER_HANDLES);
+
+        for (String category : THEME_CATEGORIES) {
+            verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + category, false, TEST_USER);
+        }
+    }
+
+    @Test
+    public void nonThemeCategorySpecified_ignored() {
+        Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
+        categoryToPackage.put("blah.category", "com.example.blah.category");
+
+        mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);
+
+        verify(mOverlayManager, never()).setEnabled("com.example.blah.category", false, TEST_USER);
+        verify(mOverlayManager, never()).setEnabledExclusiveInCategory("com.example.blah.category",
+                TEST_USER);
+    }
+
+    @Test
+    public void overlayManagerOnlyQueriedForUnspecifiedPackages() {
+        Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
+        categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
+
+        mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);
+
+        verify(mOverlayManager).getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM);
+        verify(mOverlayManager, never()).getOverlayInfosForTarget(ANDROID_PACKAGE,
+                UserHandle.SYSTEM);
+        verify(mOverlayManager, never()).getOverlayInfosForTarget(SYSUI_PACKAGE, UserHandle.SYSTEM);
+        verify(mOverlayManager, never()).getOverlayInfosForTarget(LAUNCHER_PACKAGE,
+                UserHandle.SYSTEM);
+    }
+
+    private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName,
+            String category, boolean enabled) {
+        return new OverlayInfo(packageName, targetPackageName, null, category, "",
+                enabled ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED, 0, 0, false);
+    }
+}
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index c57d4e9..b9b3a61 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -18,6 +18,10 @@
 LOCAL_MODULE := frameworks-base-overlays
 LOCAL_REQUIRED_MODULES := \
 	AccentColorBlackOverlay \
+	AccentColorCinnamonOverlay \
+	AccentColorOceanOverlay \
+	AccentColorOrchidOverlay \
+	AccentColorSpaceOverlay \
 	AccentColorGreenOverlay \
 	AccentColorPurpleOverlay \
 	DisplayCutoutEmulationCornerOverlay \
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
index 380ff34..4d844a1 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@*android:color/accent_device_default"
+    android:tint="@*android:color/accent_device_default_light"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 452a032..1973124 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_perm_group_sms.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml
similarity index 100%
rename from packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_perm_group_sms.xml
rename to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml
similarity index 100%
rename from packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml
rename to packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml
new file mode 100644
index 0000000..4e5497a
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10c5.52,0,10-4.48,10-10S17.52,2,12,2z M12,17v-1.5h7.74 c-0.24,0.53-0.54,1.03-0.88,1.5H12z M12,14v-1.5h8.47c-0.03,0.51-0.1,1.01-0.22,1.5H12z M12,11V9.5h8.12 c0.15,0.48,0.25,0.99,0.31,1.5H12z M12,8V6.5h6.47c0.39,0.46,0.74,0.96,1.03,1.5H12z M16.81,5H12V3.5C13.79,3.5,15.44,4.06,16.81,5 z M3.5,12c0-4.17,3.03-7.65,7-8.36v16.72C6.53,19.65,3.5,16.17,3.5,12z M12,18.5h5.47c-1.48,1.25-3.39,2-5.47,2V18.5z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
index 8719f15..df79827 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@*android:color/accent_device_default"
+    android:tint="@*android:color/accent_device_default_light"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 09643e6..58800c8 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_perm_group_sms.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml
similarity index 100%
rename from packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_perm_group_sms.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml
similarity index 100%
rename from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml
rename to packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml
new file mode 100644
index 0000000..6b5903c
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M11,19.93C7.06,19.44,4,16.08,4,12 c0-4.08,3.05-7.44,7-7.93V19.93z M13,4.07C14.03,4.2,15,4.52,15.87,5H13V4.07z M13,7h5.24c0.25,0.31,0.48,0.65,0.68,1H13V7z M13,19.93V19h2.87C15,19.48,14.03,19.8,13,19.93z M18.24,17H13v-1h5.92C18.72,16.35,18.49,16.69,18.24,17z M19.74,14H13v-1h6.93 C19.89,13.34,19.82,13.67,19.74,14z M19.93,11H13v-1h6.74C19.82,10.33,19.89,10.66,19.93,11z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
index d0f9d9b..feed70c 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@*android:color/accent_device_default"
+    android:tint="@*android:color/accent_device_default_light"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 3d270b3..5e1a5f2 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_perm_group_sms.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml
similarity index 100%
rename from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_perm_group_sms.xml
rename to packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml
similarity index 100%
rename from packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml
rename to packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml
new file mode 100644
index 0000000..308c2ab
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10c5.52,0,10-4.48,10-10S17.52,2,12,2z M12,12.5h8.47c-0.03,0.51-0.1,1.01-0.22,1.5 H12V12.5z M12,11V9.5h8.12c0.15,0.48,0.25,0.99,0.31,1.5H12z M12,8V6.5h6.47c0.39,0.46,0.74,0.96,1.03,1.5H12z M16.81,5H12V3.5 C13.79,3.5,15.44,4.06,16.81,5z M3.5,12c0-4.17,3.03-7.65,7-8.36v16.72C6.53,19.65,3.5,16.17,3.5,12z M12,18.5h5.47 c-1.48,1.25-3.39,2-5.47,2V18.5z M18.86,17H12v-1.5h7.74C19.5,16.03,19.2,16.53,18.86,17z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml
index 2e2ea08..2e66268 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml
@@ -21,5 +21,8 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M20.49,11.26h-1.03c-0.15-1.51-0.74-2.88-1.65-3.99l0.73-0.73c0.29-0.29,0.29-0.77,0-1.06s-0.77-0.29-1.06,0L16.75,6.2 c-1.11-0.91-2.49-1.51-4-1.66V3.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v1.04c-1.5,0.15-2.88,0.75-3.99,1.65L6.53,5.46 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L6.2,7.25c-0.91,1.11-1.51,2.49-1.66,3.99H3.51c-0.41,0-0.75,0.34-0.75,0.75 s0.34,0.75,0.75,0.75h1.03c0.15,1.51,0.74,2.88,1.65,3.99l-0.73,0.73c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22 s0.38-0.07,0.53-0.22l0.73-0.73c1.11,0.91,2.48,1.51,3.98,1.66v1.02c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-1.02 c1.48-0.14,2.86-0.71,4.01-1.65l0.73,0.73c0.15,0.15,0.34,0.22,0.53,0.22c0.19,0,0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06 l-0.72-0.72c0.94-1.14,1.51-2.52,1.66-4h1.03c0.41,0,0.75-0.34,0.75-0.75S20.9,11.26,20.49,11.26z M12,18c-3.31,0-6-2.69-6-6 s2.69-6,6-6s6,2.69,6,6S15.31,18,12,18z" />
+        android:pathData="M21.25,11.25h-2.8A6.46,6.46,0,0,0,17.09,8l2-2A0.75 0.75 ,0,0,0,18,4.93l-2,2a6.46,6.46,0,0,0-3.28-1.36V2.75a0.75 0.75 ,0,0,0-1.5,0v2.8A6.46,6.46,0,0,0,8,6.91l-2-2A0.75 0.75 ,0,0,0,4.93,6l2,2a6.46,6.46,0,0,0-1.36,3.28H2.75a0.75 0.75 ,0,0,0,0,1.5h2.8A6.46,6.46,0,0,0,6.91,16l-2,2A0.75 0.75 ,0,0,0,6,19.07l2-2a6.46,6.46,0,0,0,3.28,1.36v2.8a0.75 0.75 ,0,0,0,1.5,0v-2.8A6.46,6.46,0,0,0,16,17.09l2,2A0.75 0.75 ,0,0,0,19.07,18l-2-2a6.46,6.46,0,0,0,1.36-3.28h2.8a0.75 0.75 ,0,0,0,0-1.5ZM12,17a5,5,0,1,1,5-5A5,5,0,0,1,12,17Z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,15.5a3.5,3.5,0,0,0,0-7Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
index 2e4665e..697d1c2 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
@@ -20,9 +20,9 @@
     android:viewportWidth="24"
     android:width="24dp" >
     <path
-        android:fillColor="?android:attr/colorControlActivated"
-        android:pathData="M22.46,11.25h-3.02c-0.15-1.51-0.75-2.88-1.66-4l2.17-2.17c0.29-0.29,0.29-0.77,0-1.06s-0.77-0.29-1.06,0l-2.18,2.18 c-1.11-0.91-2.49-1.51-3.99-1.66V1.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v3.04c-1.5,0.15-2.88,0.75-3.99,1.65 L5.06,4.01C4.77,3.71,4.29,3.71,4,4.01S3.71,4.77,4,5.07l2.18,2.18c-0.91,1.11-1.51,2.48-1.66,3.98H1.48 c-0.41,0-0.75,0.34-0.75,0.75s0.34,0.75,0.75,0.75h3.04c0.15,1.51,0.74,2.88,1.65,3.99L3.99,18.9c-0.29,0.29-0.29,0.77,0,1.06 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22l2.17-2.17c1.11,0.91,2.49,1.52,3.99,1.67v3.02c0,0.41,0.34,0.75,0.75,0.75 s0.75-0.34,0.75-0.75v-3.02c1.48-0.14,2.86-0.71,4.01-1.65l2.16,2.16c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22 c0.29-0.29,0.29-0.77,0-1.06l-2.16-2.16c0.94-1.15,1.52-2.53,1.66-4.01h3.02c0.41,0,0.75-0.34,0.75-0.75S22.88,11.25,22.46,11.25z M12,18c-3.31,0-6-2.69-6-6s2.69-6,6-6s6,2.69,6,6S15.31,18,12,18z" />
-    <path
         android:fillColor="?android:attr/colorPrimary"
-        android:pathData="M 12 6 C 15.313708499 6 18 8.68629150102 18 12 C 18 15.313708499 15.313708499 18 12 18 C 8.68629150102 18 6 15.313708499 6 12 C 6 8.68629150102 8.68629150102 6 12 6 Z" />
+        android:pathData="M 12 0 L 12 0 Q 24 0 24 12 L 24 12 Q 24 24 12 24 L 12 24 Q 0 24 0 12 L 0 12 Q 0 0 12 0 Z" />
+    <path
+        android:fillColor="?android:attr/colorControlActivated"
+        android:pathData="M21.25,11.25h-2.8A6.46,6.46,0,0,0,17.09,8l2-2A0.75 0.75 ,0,0,0,18,4.93l-2,2a6.46,6.46,0,0,0-3.28-1.36V2.75a0.75 0.75 ,0,0,0-1.5,0v2.8A6.46,6.46,0,0,0,8,6.91l-2-2A0.75 0.75 ,0,0,0,4.93,6l2,2a6.46,6.46,0,0,0-1.36,3.28H2.75a0.75 0.75 ,0,0,0,0,1.5h2.8A6.46,6.46,0,0,0,6.91,16l-2,2A0.75 0.75 ,0,0,0,6,19.07l2-2a6.46,6.46,0,0,0,3.28,1.36v2.8a0.75 0.75 ,0,0,0,1.5,0v-2.8A6.46,6.46,0,0,0,16,17.09l2,2A0.75 0.75 ,0,0,0,19.07,18l-2-2a6.46,6.46,0,0,0,1.36-3.28h2.8a0.75 0.75 ,0,0,0,0-1.5ZM12,17a5,5,0,1,1,5-5A5,5,0,0,1,12,17Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
index 704ff2e..86fd47b 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
@@ -33,4 +33,8 @@
     <!-- Controls the size of the back gesture inset. -->
     <dimen name="config_backGestureInset">20dp</dimen>
 
+    <!-- Controls whether the navbar needs a scrim with
+     {@link Window#setEnsureNavigationBarContrastWhenTransparent}. -->
+    <bool name="config_navBarNeedsScrim">false</bool>
+
 </resources>
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index a88ae9e..3babb6d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7175,6 +7175,13 @@
     // Salt generation for the above hashed direct share target
     FIELD_HASHED_TARGET_SALT_GEN = 1705;
 
+    // OPEN: QS dark theme tile shown
+    // ACTION: QS dark theme tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: Q
+    QS_UI_MODE_NIGHT = 1706;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0402b8f..fdc01e0 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -704,6 +704,7 @@
             mClient.asBinder().linkToDeath(mClientVulture, 0);
         } catch (RemoteException e) {
             Slog.w(TAG, "could not set binder death listener on autofill client: " + e);
+            mClientVulture = null;
         }
     }
 
@@ -714,6 +715,7 @@
             if (!unlinked) {
                 Slog.w(TAG, "unlinking vulture from death failed for " + mActivityToken);
             }
+            mClientVulture = null;
         }
     }
 
@@ -1243,18 +1245,55 @@
      * when necessary.
      */
     public void logContextCommitted() {
-        mHandler.sendMessage(obtainMessage(
-                Session::doLogContextCommitted, this));
+        mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this));
     }
 
-    private void doLogContextCommitted() {
+    private void handleLogContextCommitted() {
+        final FillResponse lastResponse;
         synchronized (mLock) {
-            logContextCommittedLocked();
+            lastResponse = getLastResponseLocked("logContextCommited()");
+        }
+
+        if (lastResponse == null) {
+            Slog.w(TAG, "handleLogContextCommitted(): last response is null");
+            return;
+        }
+
+        // Merge UserData if necessary.
+        // Fields in packageUserData will override corresponding fields in genericUserData.
+        final UserData genericUserData = mService.getUserData();
+        final UserData packageUserData = lastResponse.getUserData();
+        final FieldClassificationUserData userData;
+        if (packageUserData == null && genericUserData == null) {
+            userData = null;
+        } else if (packageUserData != null && genericUserData != null) {
+            userData = new CompositeUserData(genericUserData, packageUserData);
+        } else if (packageUserData != null) {
+            userData = packageUserData;
+        } else {
+            userData = mService.getUserData();
+        }
+
+        final FieldClassificationStrategy fcStrategy = mService.getFieldClassificationStrategy();
+
+        // Sets field classification scores
+        if (userData != null && fcStrategy != null) {
+            logFieldClassificationScore(fcStrategy, userData);
+        } else {
+            logContextCommitted(null, null);
+        }
+    }
+
+    private void logContextCommitted(@Nullable ArrayList<AutofillId> detectedFieldIds,
+            @Nullable ArrayList<FieldClassification> detectedFieldClassifications) {
+        synchronized (mLock) {
+            logContextCommittedLocked(detectedFieldIds, detectedFieldClassifications);
         }
     }
 
     @GuardedBy("mLock")
-    private void logContextCommittedLocked() {
+    private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds,
+            @Nullable ArrayList<FieldClassification> detectedFieldClassifications) {
         final FillResponse lastResponse = getLastResponseLocked("logContextCommited()");
         if (lastResponse == null) return;
 
@@ -1308,21 +1347,6 @@
             return;
         }
 
-        // Merge UserData if necessary.
-        // Fields in packageUserData will override corresponding fields in genericUserData.
-        final UserData genericUserData = mService.getUserData();
-        final UserData packageUserData = lastResponse.getUserData();
-        final FieldClassificationUserData userData;
-        if (packageUserData == null && genericUserData == null) {
-            userData = null;
-        } else if (packageUserData != null && genericUserData != null) {
-            userData = new CompositeUserData(genericUserData, packageUserData);
-        } else if (packageUserData != null) {
-            userData = packageUserData;
-        } else {
-            userData = mService.getUserData();
-        }
-
         for (int i = 0; i < mViewStates.size(); i++) {
             final ViewState viewState = mViewStates.valueAt(i);
             final int state = viewState.getState();
@@ -1447,33 +1471,18 @@
             }
         }
 
-        // Sets field classification scores
-        final FieldClassificationStrategy fcStrategy = mService.getFieldClassificationStrategy();
-        if (userData != null && fcStrategy != null) {
-            logFieldClassificationScoreLocked(fcStrategy, ignoredDatasets, changedFieldIds,
-                    changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                    userData, mViewStates.values());
-        } else {
-            mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
-                    ignoredDatasets, changedFieldIds, changedDatasetIds,
-                    manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                    mComponentName, mCompatMode);
-        }
+        mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
+                ignoredDatasets, changedFieldIds, changedDatasetIds,
+                manuallyFilledFieldIds, manuallyFilledDatasetIds, detectedFieldIds,
+                detectedFieldClassifications, mComponentName, mCompatMode);
     }
 
     /**
      * Adds the matches to {@code detectedFieldsIds} and {@code detectedFieldClassifications} for
      * {@code fieldId} based on its {@code currentValue} and {@code userData}.
      */
-    private void logFieldClassificationScoreLocked(
-            @NonNull FieldClassificationStrategy fcStrategy,
-            @NonNull ArraySet<String> ignoredDatasets,
-            @NonNull ArrayList<AutofillId> changedFieldIds,
-            @NonNull ArrayList<String> changedDatasetIds,
-            @NonNull ArrayList<AutofillId> manuallyFilledFieldIds,
-            @NonNull ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
-            @NonNull FieldClassificationUserData userData,
-            @NonNull Collection<ViewState> viewStates) {
+    private void logFieldClassificationScore(@NonNull FieldClassificationStrategy fcStrategy,
+            @NonNull FieldClassificationUserData userData) {
 
         final String[] userValues = userData.getValues();
         final String[] categoryIds = userData.getCategoryIds();
@@ -1499,6 +1508,11 @@
         final ArrayList<FieldClassification> detectedFieldClassifications = new ArrayList<>(
                 maxFieldsSize);
 
+        final Collection<ViewState> viewStates;
+        synchronized (mLock) {
+            viewStates = mViewStates.values();
+        }
+
         final int viewsSize = viewStates.size();
 
         // First, we get all scores.
@@ -1514,10 +1528,7 @@
         final RemoteCallback callback = new RemoteCallback((result) -> {
             if (result == null) {
                 if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
-                mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
-                        ignoredDatasets, changedFieldIds, changedDatasetIds,
-                        manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                        mComponentName, mCompatMode);
+                logContextCommitted(null, null);
                 return;
             }
             final Scores scores = result.getParcelable(EXTRA_SCORES);
@@ -1544,7 +1555,7 @@
                             final Float currentScore = scoresByField.get(categoryId);
                             if (currentScore != null && currentScore > score) {
                                 if (sVerbose) {
-                                    Slog.v(TAG,  "skipping score " + score
+                                    Slog.v(TAG, "skipping score " + score
                                             + " because it's less than " + currentScore);
                                 }
                                 continue;
@@ -1554,8 +1565,7 @@
                                         + autofillId);
                             }
                             scoresByField.put(categoryId, score);
-                        }
-                        else if (sVerbose) {
+                        } else if (sVerbose) {
                             Slog.v(TAG, "skipping score 0 at index " + j + " and id " + autofillId);
                         }
                     }
@@ -1579,10 +1589,7 @@
                 return;
             }
 
-            mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
-                    ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
-                    manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
-                    mComponentName, mCompatMode);
+            logContextCommitted(detectedFieldIds, detectedFieldClassifications);
         });
 
         fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index a3e7d36..54a3ecb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -166,6 +166,9 @@
     @Override
     public void onUnlockUser(int userHandle) {
         Set<Association> associations = readAllAssociations(userHandle);
+        if (associations == null || associations.isEmpty()) {
+            return;
+        }
         Set<String> companionAppPackages = new HashSet<>();
         for (Association association : associations) {
             companionAppPackages.add(association.companionAppPackage);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 47c85683..1bd367c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1764,7 +1764,8 @@
                                 + ", callingPackage: " + callingPackage;
                 // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
                 Slog.wtf(TAG, errorMsg);
-                throw new UnsupportedOperationException(errorMsg);
+                // TODO b/129995049: Resume throwing once issue is resolved.
+                // throw new UnsupportedOperationException(errorMsg);
             }
             setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
                     interval, operation, directReceiver, listenerTag, flags, true, workSource,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6405254..e4c39cc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -108,7 +108,6 @@
 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;
@@ -133,6 +132,7 @@
 import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -237,6 +237,16 @@
 
     private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
 
+    /**
+     * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
+     * by OEMs for configuration purposes, as this value is overridden by
+     * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+     * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
+     * (preferably via runtime resource overlays).
+     */
+    private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL =
+            "http://connectivitycheck.gstatic.com/generate_204";
+
     // TODO: create better separation between radio types and network types
 
     // how long to wait before switching back to a radio's default network
@@ -1628,8 +1638,11 @@
      */
     private boolean disallowedBecauseSystemCaller() {
         // TODO: start throwing a SecurityException when GnssLocationProvider stops calling
-        // requestRouteToHost.
-        if (isSystem(Binder.getCallingUid())) {
+        // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost
+        // for devices launched with Q and above. However, existing devices upgrading to Q and
+        // above must continued to be supported for few more releases.
+        if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt(
+                "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) {
             log("This method exists only for app backwards compatibility"
                     + " and must not be called by system services.");
             return true;
@@ -1767,11 +1780,8 @@
             // caller type. Need to re-factor NetdEventListenerService to allow multiple
             // NetworkMonitor registrants.
             if (nai != null && nai.satisfies(mDefaultRequest)) {
-                try {
-                    nai.networkMonitor().notifyDnsResponse(returnCode);
-                } catch (RemoteException e) {
-                    e.rethrowFromSystemServer();
-                }
+                Binder.withCleanCallingIdentity(() ->
+                        nai.networkMonitor().notifyDnsResponse(returnCode));
             }
         }
 
@@ -6542,7 +6552,7 @@
                         uid, newRules, metered, mRestrictBackground);
             }
             if (oldBlocked == newBlocked) {
-                return;
+                continue;
             }
             final int arg = encodeBool(newBlocked);
             for (int i = 0; i < nai.numNetworkRequests(); i++) {
@@ -6700,9 +6710,20 @@
     @Override
     public String getCaptivePortalServerUrl() {
         enforceConnectivityInternalPermission();
-        final String defaultUrl = mContext.getResources().getString(
-                R.string.config_networkDefaultCaptivePortalServerUrl);
-        return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext, defaultUrl);
+        String settingUrl = mContext.getResources().getString(
+                R.string.config_networkCaptivePortalServerUrl);
+
+        if (!TextUtils.isEmpty(settingUrl)) {
+            return settingUrl;
+        }
+
+        settingUrl = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+        if (!TextUtils.isEmpty(settingUrl)) {
+            return settingUrl;
+        }
+
+        return DEFAULT_CAPTIVE_PORTAL_HTTP_URL;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 99bbcf8..f1882c5 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -47,7 +47,7 @@
     private static IGsiService connect(DeathRecipient recipient) throws RemoteException {
         IBinder binder = ServiceManager.getService("gsiservice");
         if (binder == null) {
-            throw new RemoteException(NO_SERVICE_ERROR);
+            return null;
         }
         /**
          * The init will restart gsiservice if it crashed and the proxy object will need to be
@@ -68,26 +68,31 @@
 
     private IGsiService getGsiService() throws RemoteException {
         checkPermission();
+
         if (!"running".equals(SystemProperties.get("init.svc.gsid"))) {
             SystemProperties.set("ctl.start", "gsid");
-            for (int sleepMs = 64; sleepMs <= (GSID_ROUGH_TIMEOUT_MS << 1); sleepMs <<= 1) {
-                try {
-                    Thread.sleep(sleepMs);
-                } catch (InterruptedException e) {
-                    Slog.e(TAG, "Interrupted when waiting for GSID");
-                    break;
+        }
+
+        for (int sleepMs = 64; sleepMs <= (GSID_ROUGH_TIMEOUT_MS << 1); sleepMs <<= 1) {
+            synchronized (this) {
+                if (mGsiService == null) {
+                    mGsiService = connect(this);
                 }
-                if ("running".equals(SystemProperties.get("init.svc.gsid"))) {
-                    break;
+                if (mGsiService != null) {
+                    return mGsiService;
                 }
             }
-        }
-        synchronized (this) {
-            if (mGsiService == null) {
-                mGsiService = connect(this);
+
+            try {
+                Slog.d(TAG, "GsiService is not ready, wait for " + sleepMs + "ms");
+                Thread.sleep(sleepMs);
+            } catch (InterruptedException e) {
+                Slog.e(TAG, "Interrupted when waiting for GSID");
+                return null;
             }
-            return mGsiService;
         }
+
+        throw new RemoteException(NO_SERVICE_ERROR);
     }
 
     private void checkPermission() {
diff --git a/services/core/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
index 27ad208..19ab33e 100644
--- a/services/core/java/com/android/server/ExplicitHealthCheckController.java
+++ b/services/core/java/com/android/server/ExplicitHealthCheckController.java
@@ -35,7 +35,9 @@
 import android.os.UserHandle;
 import android.service.watchdog.ExplicitHealthCheckService;
 import android.service.watchdog.IExplicitHealthCheckService;
+import android.service.watchdog.PackageInfo;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -69,7 +71,7 @@
     // To prevent deadlocks between the controller and watchdog threads, we have
     // a lock invariant to ALWAYS acquire the PackageWatchdog#mLock before #mLock in this class.
     // It's easier to just NOT hold #mLock when calling into watchdog code on this consumer.
-    @GuardedBy("mLock") @Nullable private Consumer<List<String>> mSupportedConsumer;
+    @GuardedBy("mLock") @Nullable private Consumer<List<PackageInfo>> mSupportedConsumer;
     // Called everytime we need to notify the watchdog to sync requests between itself and the
     // health check service. In practice, should never be null after it has been #setEnabled.
     // To prevent deadlocks between the controller and watchdog threads, we have
@@ -104,7 +106,7 @@
      * ensure a happens-before relationship of the set parameters and visibility on other threads.
      */
     public void setCallbacks(Consumer<String> passedConsumer,
-            Consumer<List<String>> supportedConsumer, Runnable notifySyncRunnable) {
+            Consumer<List<PackageInfo>> supportedConsumer, Runnable notifySyncRunnable) {
         synchronized (mLock) {
             if (mPassedConsumer != null || mSupportedConsumer != null
                     || mNotifySyncRunnable != null) {
@@ -144,14 +146,18 @@
             return;
         }
 
-        getSupportedPackages(supportedPackages -> {
+        getSupportedPackages(supportedPackageInfos -> {
             // Notify the watchdog without lock held
-            mSupportedConsumer.accept(supportedPackages);
+            mSupportedConsumer.accept(supportedPackageInfos);
             getRequestedPackages(previousRequestedPackages -> {
                 synchronized (mLock) {
                     // Hold lock so requests and cancellations are sent atomically.
                     // It is important we don't mix requests from multiple threads.
 
+                    Set<String> supportedPackages = new ArraySet<>();
+                    for (PackageInfo info : supportedPackageInfos) {
+                        supportedPackages.add(info.getPackageName());
+                    }
                     // Note, this may modify newRequestedPackages
                     newRequestedPackages.retainAll(supportedPackages);
 
@@ -229,7 +235,7 @@
      * Returns the packages that we can request explicit health checks for.
      * The packages will be returned to the {@code consumer}.
      */
-    private void getSupportedPackages(Consumer<List<String>> consumer) {
+    private void getSupportedPackages(Consumer<List<PackageInfo>> consumer) {
         synchronized (mLock) {
             if (!prepareServiceLocked("get health check supported packages")) {
                 return;
@@ -238,7 +244,8 @@
             Slog.d(TAG, "Getting health check supported packages");
             try {
                 mRemoteService.getSupportedPackages(new RemoteCallback(result -> {
-                    List<String> packages = result.getStringArrayList(EXTRA_SUPPORTED_PACKAGES);
+                    List<PackageInfo> packages =
+                            result.getParcelableArrayList(EXTRA_SUPPORTED_PACKAGES);
                     Slog.i(TAG, "Explicit health check supported packages " + packages);
                     consumer.accept(packages);
                 }));
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 126bf65..2055b64 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -96,9 +96,10 @@
             new int[] {OsConstants.AF_INET, OsConstants.AF_INET6};
 
     private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
-    private static final int MAX_PORT_BIND_ATTEMPTS = 10;
     private static final InetAddress INADDR_ANY;
 
+    @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10;
+
     static {
         try {
             INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
@@ -207,6 +208,7 @@
                     mBinder.linkToDeath(this, 0);
                 } catch (RemoteException e) {
                     binderDied();
+                    e.rethrowFromSystemServer();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 0c681df..7d0d834 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.service.watchdog.PackageInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -57,6 +58,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -102,16 +104,10 @@
     private boolean mIsHealthCheckEnabled = true;
     @GuardedBy("mLock")
     private boolean mIsPackagesReady;
-    // SystemClock#uptimeMillis when we last executed #pruneObservers.
+    // SystemClock#uptimeMillis when we last executed #syncState
     // 0 if no prune is scheduled.
     @GuardedBy("mLock")
-    private long mUptimeAtLastPruneMs;
-    // Duration in millis that the last prune was scheduled for.
-    // Used along with #mUptimeAtLastPruneMs after scheduling a prune to determine the remaining
-    // duration before #pruneObservers will be executed.
-    // 0 if no prune is scheduled.
-    @GuardedBy("mLock")
-    private long mDurationAtLastPrune;
+    private long mUptimeAtLastStateSync;
 
     private PackageWatchdog(Context context) {
         // Needs to be constructed inline
@@ -156,7 +152,7 @@
             mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
                     packages -> onSupportedPackages(packages),
                     () -> syncRequestsAsync());
-            // Controller is initially disabled until here where we may enable it and sync requests
+            // Controller is initially disabled until here where we may enable it and sync our state
             setExplicitHealthCheckEnabled(mIsHealthCheckEnabled);
         }
     }
@@ -173,10 +169,6 @@
             if (internalObserver != null) {
                 internalObserver.mRegisteredObserver = observer;
             }
-            if (mDurationAtLastPrune == 0) {
-                // Nothing running, prune
-                pruneAndSchedule();
-            }
         }
     }
 
@@ -214,6 +206,12 @@
             packages.add(new MonitoredPackage(packageNames.get(i), durationMs, false));
         }
 
+        // Sync before we add the new packages to the observers. This will #pruneObservers,
+        // causing any elapsed time to be deducted from all existing packages before we add new
+        // packages. This maintains the invariant that the elapsed time for ALL (new and existing)
+        // packages is the same.
+        syncState("observing new packages");
+
         synchronized (mLock) {
             ObserverInternal oldObserver = mAllObservers.get(observer.getName());
             if (oldObserver == null) {
@@ -224,16 +222,16 @@
             } else {
                 Slog.d(TAG, observer.getName() + " added the following "
                         + "packages to monitor " + packageNames);
-                oldObserver.updatePackages(packages);
+                oldObserver.updatePackagesLocked(packages);
             }
         }
+
+        // Register observer in case not already registered
         registerHealthObserver(observer);
-        // Always prune because we may have received packges requiring an earlier
-        // schedule than we are currently scheduled for.
-        pruneAndSchedule();
-        Slog.i(TAG, "Syncing health check requests, observing packages " + packageNames);
-        syncRequestsAsync();
-        saveToFileAsync();
+
+        // Sync after we add the new packages to the observers. We may have received packges
+        // requiring an earlier schedule than we are currently scheduled for.
+        syncState("updated observers");
     }
 
     /**
@@ -245,7 +243,7 @@
         synchronized (mLock) {
             mAllObservers.remove(observer.getName());
         }
-        saveToFileAsync();
+        syncState("unregistering observer: " + observer.getName());
     }
 
     /**
@@ -296,7 +294,8 @@
                         ObserverInternal observer = mAllObservers.valueAt(oIndex);
                         PackageHealthObserver registeredObserver = observer.mRegisteredObserver;
                         if (registeredObserver != null
-                                && observer.onPackageFailure(versionedPackage.getPackageName())) {
+                                && observer.onPackageFailureLocked(
+                                        versionedPackage.getPackageName())) {
                             int impact = registeredObserver.onHealthCheckFailed(versionedPackage);
                             if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
                                     && impact < currentObserverImpact) {
@@ -321,9 +320,11 @@
     /** Writes the package information to file during shutdown. */
     public void writeNow() {
         synchronized (mLock) {
+            // Must only run synchronous tasks as this runs on the ShutdownThread and no other
+            // thread is guaranteed to run during shutdown.
             if (!mAllObservers.isEmpty()) {
-                mLongTaskHandler.removeCallbacks(this::saveToFile);
-                pruneObservers(SystemClock.uptimeMillis() - mUptimeAtLastPruneMs);
+                mLongTaskHandler.removeCallbacks(this::saveToFileAsync);
+                pruneObserversLocked();
                 saveToFile();
                 Slog.i(TAG, "Last write to update package durations");
             }
@@ -341,9 +342,8 @@
         synchronized (mLock) {
             mIsHealthCheckEnabled = enabled;
             mHealthCheckController.setEnabled(enabled);
-            Slog.i(TAG, "Syncing health check requests, explicit health check is "
-                    + (enabled ? "enabled" : "disabled"));
-            syncRequestsAsync();
+            // Prune to update internal state whenever health check is enabled/disabled
+            syncState("health check state " + (enabled ? "enabled" : "disabled"));
         }
     }
 
@@ -393,9 +393,8 @@
      * Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}.
      */
     private void syncRequestsAsync() {
-        if (!mShortTaskHandler.hasCallbacks(this::syncRequests)) {
-            mShortTaskHandler.post(this::syncRequests);
-        }
+        mShortTaskHandler.removeCallbacks(this::syncRequests);
+        mShortTaskHandler.post(this::syncRequests);
     }
 
     /**
@@ -414,6 +413,7 @@
 
         // Call outside lock to avoid holding lock when calling into the controller.
         if (packages != null) {
+            Slog.i(TAG, "Syncing health check requests for packages: " + packages);
             mHealthCheckController.syncRequests(packages);
         }
     }
@@ -426,86 +426,73 @@
      * effectively behave as if the explicit health check hasn't passed for {@code packageName}.
      *
      * <p> {@code packageName} can still be considered failed if reported by
-     * {@link #onPackageFailure} before the package expires.
+     * {@link #onPackageFailureLocked} before the package expires.
      *
      * <p> Triggered by components outside the system server when they are fully functional after an
      * update.
      */
     private void onHealthCheckPassed(String packageName) {
         Slog.i(TAG, "Health check passed for package: " + packageName);
-        boolean shouldUpdateFile = false;
+        boolean isStateChanged = false;
+
         synchronized (mLock) {
             for (int observerIdx = 0; observerIdx < mAllObservers.size(); observerIdx++) {
                 ObserverInternal observer = mAllObservers.valueAt(observerIdx);
                 MonitoredPackage monitoredPackage = observer.mPackages.get(packageName);
-                if (monitoredPackage != null && !monitoredPackage.mHasPassedHealthCheck) {
-                    monitoredPackage.mHasPassedHealthCheck = true;
-                    shouldUpdateFile = true;
+
+                if (monitoredPackage != null) {
+                    int oldState = monitoredPackage.getHealthCheckStateLocked();
+                    int newState = monitoredPackage.tryPassHealthCheckLocked();
+                    isStateChanged |= oldState != newState;
                 }
             }
         }
 
-        // So we can unbind from the service if this was the last result we expected
-        Slog.i(TAG, "Syncing health check requests, health check passed for " + packageName);
-        syncRequestsAsync();
-
-        if (shouldUpdateFile) {
-            saveToFileAsync();
+        if (isStateChanged) {
+            syncState("health check passed for " + packageName);
         }
     }
 
-    private void onSupportedPackages(List<String> supportedPackages) {
-        boolean shouldUpdateFile = false;
-        boolean shouldPrune = false;
+    private void onSupportedPackages(List<PackageInfo> supportedPackages) {
+        boolean isStateChanged = false;
+
+        Map<String, Long> supportedPackageTimeouts = new ArrayMap<>();
+        Iterator<PackageInfo> it = supportedPackages.iterator();
+        while (it.hasNext()) {
+            PackageInfo info = it.next();
+            supportedPackageTimeouts.put(info.getPackageName(), info.getHealthCheckTimeoutMillis());
+        }
 
         synchronized (mLock) {
             Slog.d(TAG, "Received supported packages " + supportedPackages);
             Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
             while (oit.hasNext()) {
-                ObserverInternal observer = oit.next();
-                Iterator<MonitoredPackage> pit =
-                        observer.mPackages.values().iterator();
+                Iterator<MonitoredPackage> pit = oit.next().mPackages.values().iterator();
                 while (pit.hasNext()) {
                     MonitoredPackage monitoredPackage = pit.next();
-                    String packageName = monitoredPackage.mName;
-                    int healthCheckState = monitoredPackage.getHealthCheckState();
+                    String packageName = monitoredPackage.getName();
+                    int oldState = monitoredPackage.getHealthCheckStateLocked();
+                    int newState;
 
-                    if (healthCheckState != MonitoredPackage.STATE_PASSED) {
-                        // Have to update file, we will either transition state or reduce
-                        // health check duration
-                        shouldUpdateFile = true;
-
-                        if (supportedPackages.contains(packageName)) {
-                            // Supports health check, transition to ACTIVE if not already.
-                            // We need to prune packages earlier than already scheduled.
-                            shouldPrune = true;
-
-                            // TODO: Get healthCheckDuration from supportedPackages
-                            long healthCheckDuration = monitoredPackage.mDurationMs;
-                            monitoredPackage.mHealthCheckDurationMs = Math.min(healthCheckDuration,
-                                    monitoredPackage.mDurationMs);
-                            Slog.i(TAG, packageName + " health check state is now: ACTIVE("
-                                    + monitoredPackage.mHealthCheckDurationMs + "ms)");
-                        } else {
-                            // Does not support health check, transistion to PASSED
-                            monitoredPackage.mHasPassedHealthCheck = true;
-                            Slog.i(TAG, packageName + " health check state is now: PASSED");
-                        }
+                    if (supportedPackageTimeouts.containsKey(packageName)) {
+                        // Supported packages become ACTIVE if currently INACTIVE
+                        newState = monitoredPackage.setHealthCheckActiveLocked(
+                                supportedPackageTimeouts.get(packageName));
                     } else {
-                        Slog.i(TAG, packageName + " does not support health check, state: PASSED");
+                        // Unsupported packages are marked as PASSED unless already FAILED
+                        newState = monitoredPackage.tryPassHealthCheckLocked();
                     }
+                    isStateChanged |= oldState != newState;
                 }
             }
         }
 
-        if (shouldUpdateFile) {
-            saveToFileAsync();
-        }
-        if (shouldPrune) {
-            pruneAndSchedule();
+        if (isStateChanged) {
+            syncState("updated health check supported packages " + supportedPackages);
         }
     }
 
+    @GuardedBy("mLock")
     private Set<String> getPackagesPendingHealthChecksLocked() {
         Slog.d(TAG, "Getting all observed packages pending health checks");
         Set<String> packages = new ArraySet<>();
@@ -516,8 +503,9 @@
                     observer.mPackages.values().iterator();
             while (pit.hasNext()) {
                 MonitoredPackage monitoredPackage = pit.next();
-                String packageName = monitoredPackage.mName;
-                if (!monitoredPackage.mHasPassedHealthCheck) {
+                String packageName = monitoredPackage.getName();
+                if (monitoredPackage.getHealthCheckStateLocked()
+                        != MonitoredPackage.STATE_PASSED) {
                     packages.add(packageName);
                 }
             }
@@ -525,88 +513,91 @@
         return packages;
     }
 
-    /** Executes {@link #pruneObservers} and schedules the next execution. */
-    private void pruneAndSchedule() {
+    /**
+     * Syncs the state of the observers.
+     *
+     * <p> Prunes all observers, saves new state to disk, syncs health check requests with the
+     * health check service and schedules the next state sync.
+     */
+    private void syncState(String reason) {
         synchronized (mLock) {
-            long nextDurationToScheduleMs = getNextPruneScheduleMillisLocked();
-            if (nextDurationToScheduleMs == Long.MAX_VALUE) {
-                Slog.i(TAG, "No monitored packages, ending prune");
-                mDurationAtLastPrune = 0;
-                mUptimeAtLastPruneMs = 0;
-                return;
-            }
-            long uptimeMs = SystemClock.uptimeMillis();
-            // O if not running
-            long elapsedDurationMs = mUptimeAtLastPruneMs == 0
-                    ? 0 : uptimeMs - mUptimeAtLastPruneMs;
-            // Less than O if unexpectedly didn't run yet even though
-            // we are past the last duration scheduled to run
-            long remainingDurationMs = mDurationAtLastPrune - elapsedDurationMs;
-            if (mUptimeAtLastPruneMs == 0
-                    || remainingDurationMs <= 0
-                    || nextDurationToScheduleMs < remainingDurationMs) {
-                // First schedule or an earlier reschedule
-                pruneObservers(elapsedDurationMs);
-                // We don't use Handler#hasCallbacks because we want to update the schedule delay
-                mShortTaskHandler.removeCallbacks(this::pruneAndSchedule);
-                mShortTaskHandler.postDelayed(this::pruneAndSchedule, nextDurationToScheduleMs);
-                mDurationAtLastPrune = nextDurationToScheduleMs;
-                mUptimeAtLastPruneMs = uptimeMs;
-            }
+            Slog.i(TAG, "Syncing state, reason: " + reason);
+            pruneObserversLocked();
+
+            saveToFileAsync();
+            syncRequestsAsync();
+
+            // Done syncing state, schedule the next state sync
+            scheduleNextSyncStateLocked();
+        }
+    }
+
+    private void syncStateWithScheduledReason() {
+        syncState("scheduled");
+    }
+
+    @GuardedBy("mLock")
+    private void scheduleNextSyncStateLocked() {
+        long durationMs = getNextStateSyncMillisLocked();
+        mShortTaskHandler.removeCallbacks(this::syncStateWithScheduledReason);
+        if (durationMs == Long.MAX_VALUE) {
+            Slog.i(TAG, "Cancelling state sync, nothing to sync");
+            mUptimeAtLastStateSync = 0;
+        } else {
+            Slog.i(TAG, "Scheduling next state sync in " + durationMs + "ms");
+            mUptimeAtLastStateSync = SystemClock.uptimeMillis();
+            mShortTaskHandler.postDelayed(this::syncStateWithScheduledReason, durationMs);
         }
     }
 
     /**
-     * Returns the next time in millis to schedule a prune.
+     * Returns the next duration in millis to sync the watchdog state.
      *
      * @returns Long#MAX_VALUE if there are no observed packages.
      */
-    private long getNextPruneScheduleMillisLocked() {
+    @GuardedBy("mLock")
+    private long getNextStateSyncMillisLocked() {
         long shortestDurationMs = Long.MAX_VALUE;
         for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
             ArrayMap<String, MonitoredPackage> packages = mAllObservers.valueAt(oIndex).mPackages;
             for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
                 MonitoredPackage mp = packages.valueAt(pIndex);
-                long duration = Math.min(mp.mDurationMs, mp.mHealthCheckDurationMs);
+                long duration = mp.getShortestScheduleDurationMsLocked();
                 if (duration < shortestDurationMs) {
                     shortestDurationMs = duration;
                 }
             }
         }
-        Slog.i(TAG, "Next prune will be scheduled in " + shortestDurationMs + "ms");
-
         return shortestDurationMs;
     }
 
     /**
-     * Removes {@code elapsedMs} milliseconds from all durations on monitored packages.
-     *
-     * <p> Prunes all observers with {@link ObserverInternal#prunePackages} and discards observers
-     * without any packages left.
+     * Removes {@code elapsedMs} milliseconds from all durations on monitored packages
+     * and updates other internal state.
      */
-    private void pruneObservers(long elapsedMs) {
-        if (elapsedMs == 0) {
+    @GuardedBy("mLock")
+    private void pruneObserversLocked() {
+        long elapsedMs = mUptimeAtLastStateSync == 0
+                ? 0 : SystemClock.uptimeMillis() - mUptimeAtLastStateSync;
+        if (elapsedMs <= 0) {
+            Slog.i(TAG, "Not pruning observers, elapsed time: " + elapsedMs + "ms");
             return;
         }
-        synchronized (mLock) {
-            Slog.d(TAG, "Removing expired packages after " + elapsedMs + "ms");
-            Iterator<ObserverInternal> it = mAllObservers.values().iterator();
-            while (it.hasNext()) {
-                ObserverInternal observer = it.next();
-                Set<MonitoredPackage> failedPackages =
-                        observer.prunePackages(elapsedMs);
-                if (!failedPackages.isEmpty()) {
-                    onHealthCheckFailed(observer, failedPackages);
-                }
-                if (observer.mPackages.isEmpty()) {
-                    Slog.i(TAG, "Discarding observer " + observer.mName + ". All packages expired");
-                    it.remove();
-                }
+
+        Slog.i(TAG, "Removing " + elapsedMs + "ms from all packages on all observers");
+        Iterator<ObserverInternal> it = mAllObservers.values().iterator();
+        while (it.hasNext()) {
+            ObserverInternal observer = it.next();
+            Set<MonitoredPackage> failedPackages =
+                    observer.prunePackagesLocked(elapsedMs);
+            if (!failedPackages.isEmpty()) {
+                onHealthCheckFailed(observer, failedPackages);
+            }
+            if (observer.mPackages.isEmpty()) {
+                Slog.i(TAG, "Discarding observer " + observer.mName + ". All packages expired");
+                it.remove();
             }
         }
-        Slog.i(TAG, "Syncing health check requests, pruned observers");
-        syncRequestsAsync();
-        saveToFileAsync();
     }
 
     private void onHealthCheckFailed(ObserverInternal observer,
@@ -618,7 +609,7 @@
                     PackageManager pm = mContext.getPackageManager();
                     Iterator<MonitoredPackage> it = failedPackages.iterator();
                     while (it.hasNext()) {
-                        String failedPackage = it.next().mName;
+                        String failedPackage = it.next().getName();
                         long versionCode = 0;
                         Slog.i(TAG, "Explicit health check failed for package " + failedPackage);
                         try {
@@ -673,6 +664,7 @@
      * Persists mAllObservers to file. Threshold information is ignored.
      */
     private boolean saveToFile() {
+        Slog.i(TAG, "Saving observer state to file");
         synchronized (mLock) {
             FileOutputStream stream;
             try {
@@ -689,7 +681,7 @@
                 out.startTag(null, TAG_PACKAGE_WATCHDOG);
                 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
                 for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
-                    mAllObservers.valueAt(oIndex).write(out);
+                    mAllObservers.valueAt(oIndex).writeLocked(out);
                 }
                 out.endTag(null, TAG_PACKAGE_WATCHDOG);
                 out.endDocument();
@@ -730,7 +722,7 @@
 
         ObserverInternal(String name, List<MonitoredPackage> packages) {
             mName = name;
-            updatePackages(packages);
+            updatePackagesLocked(packages);
         }
 
         /**
@@ -738,20 +730,13 @@
          * Does not persist any package failure thresholds.
          */
         @GuardedBy("mLock")
-        public boolean write(XmlSerializer out) {
+        public boolean writeLocked(XmlSerializer out) {
             try {
                 out.startTag(null, TAG_OBSERVER);
                 out.attribute(null, ATTR_NAME, mName);
                 for (int i = 0; i < mPackages.size(); i++) {
                     MonitoredPackage p = mPackages.valueAt(i);
-                    out.startTag(null, TAG_PACKAGE);
-                    out.attribute(null, ATTR_NAME, p.mName);
-                    out.attribute(null, ATTR_DURATION, String.valueOf(p.mDurationMs));
-                    out.attribute(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION,
-                            String.valueOf(p.mHealthCheckDurationMs));
-                    out.attribute(null, ATTR_PASSED_HEALTH_CHECK,
-                            String.valueOf(p.mHasPassedHealthCheck));
-                    out.endTag(null, TAG_PACKAGE);
+                    p.writeLocked(out);
                 }
                 out.endTag(null, TAG_OBSERVER);
                 return true;
@@ -762,7 +747,7 @@
         }
 
         @GuardedBy("mLock")
-        public void updatePackages(List<MonitoredPackage> packages) {
+        public void updatePackagesLocked(List<MonitoredPackage> packages) {
             for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
                 MonitoredPackage p = packages.get(pIndex);
                 mPackages.put(p.mName, p);
@@ -775,37 +760,24 @@
          * observation. If any health check duration is less than 0, the health check result
          * is evaluated.
          *
-         * @returns a {@link Set} of packages that were removed from the observer without explicit
+         * @return a {@link Set} of packages that were removed from the observer without explicit
          * health check passing, or an empty list if no package expired for which an explicit health
          * check was still pending
          */
         @GuardedBy("mLock")
-        private Set<MonitoredPackage> prunePackages(long elapsedMs) {
+        private Set<MonitoredPackage> prunePackagesLocked(long elapsedMs) {
             Set<MonitoredPackage> failedPackages = new ArraySet<>();
             Iterator<MonitoredPackage> it = mPackages.values().iterator();
             while (it.hasNext()) {
                 MonitoredPackage p = it.next();
-                int healthCheckState = p.getHealthCheckState();
-
-                // Handle health check timeouts
-                if (healthCheckState == MonitoredPackage.STATE_ACTIVE) {
-                    // Only reduce duration if state is active
-                    p.mHealthCheckDurationMs -= elapsedMs;
-                    // Check duration after reducing duration
-                    if (p.mHealthCheckDurationMs <= 0) {
-                        failedPackages.add(p);
-                    }
+                int oldState = p.getHealthCheckStateLocked();
+                int newState = p.handleElapsedTimeLocked(elapsedMs);
+                if (oldState != MonitoredPackage.STATE_FAILED
+                        && newState == MonitoredPackage.STATE_FAILED) {
+                    Slog.i(TAG, "Package " + p.mName + " failed health check");
+                    failedPackages.add(p);
                 }
-
-                // Handle package expiry
-                p.mDurationMs -= elapsedMs;
-                // Check duration after reducing duration
-                if (p.mDurationMs <= 0) {
-                    if (healthCheckState == MonitoredPackage.STATE_INACTIVE) {
-                        Slog.w(TAG, "Package " + p.mName
-                                + " expiring without starting health check, failing");
-                        failedPackages.add(p);
-                    }
+                if (p.isExpiredLocked()) {
                     it.remove();
                 }
             }
@@ -817,10 +789,10 @@
          * @returns {@code true} if failure threshold is exceeded, {@code false} otherwise
          */
         @GuardedBy("mLock")
-        public boolean onPackageFailure(String packageName) {
+        public boolean onPackageFailureLocked(String packageName) {
             MonitoredPackage p = mPackages.get(packageName);
             if (p != null) {
-                return p.onFailure();
+                return p.onFailureLocked();
             }
             return false;
         }
@@ -877,33 +849,45 @@
     }
 
     /**
-     * Represents a package along with the time it should be monitored for.
+     * Represents a package and its health check state along with the time
+     * it should be monitored for.
      *
      * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
      * instances of this class.
      */
-    //TODO(b/120598832): Remove 'm' from non-private fields
-    private static class MonitoredPackage {
+    static class MonitoredPackage {
         // Health check states
+        // TODO(b/120598832): Prefix with HEALTH_CHECK
         // mName has not passed health check but has requested a health check
-        public static int STATE_ACTIVE = 0;
+        public static final int STATE_ACTIVE = 0;
         // mName has not passed health check and has not requested a health check
-        public static int STATE_INACTIVE = 1;
+        public static final int STATE_INACTIVE = 1;
         // mName has passed health check
-        public static int STATE_PASSED = 2;
+        public static final int STATE_PASSED = 2;
+        // mName has failed health check
+        public static final int STATE_FAILED = 3;
 
-        public final String mName;
-        // Whether an explicit health check has passed
+        //TODO(b/120598832): VersionedPackage?
+        private final String mName;
+        // One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
+        // methods that could change the health check state: handleElapsedTimeLocked and
+        // tryPassHealthCheckLocked
+        private int mHealthCheckState = STATE_INACTIVE;
+        // Whether an explicit health check has passed.
+        // This value in addition with mHealthCheckDurationMs determines the health check state
+        // of the package, see #getHealthCheckStateLocked
         @GuardedBy("mLock")
-        public boolean mHasPassedHealthCheck;
-        // System uptime duration to monitor package
+        private boolean mHasPassedHealthCheck;
+        // System uptime duration to monitor package.
         @GuardedBy("mLock")
-        public long mDurationMs;
+        private long mDurationMs;
         // System uptime duration to check the result of an explicit health check
         // Initially, MAX_VALUE until we get a value from the health check service
         // and request health checks.
+        // This value in addition with mHasPassedHealthCheck determines the health check state
+        // of the package, see #getHealthCheckStateLocked
         @GuardedBy("mLock")
-        public long mHealthCheckDurationMs = Long.MAX_VALUE;
+        private long mHealthCheckDurationMs = Long.MAX_VALUE;
         // System uptime of first package failure
         @GuardedBy("mLock")
         private long mUptimeStartMs;
@@ -921,6 +905,20 @@
             mDurationMs = durationMs;
             mHealthCheckDurationMs = healthCheckDurationMs;
             mHasPassedHealthCheck = hasPassedHealthCheck;
+            updateHealthCheckStateLocked();
+        }
+
+        /** Writes the salient fields to disk using {@code out}. */
+        @GuardedBy("mLock")
+        public void writeLocked(XmlSerializer out) throws IOException {
+            out.startTag(null, TAG_PACKAGE);
+            out.attribute(null, ATTR_NAME, mName);
+            out.attribute(null, ATTR_DURATION, String.valueOf(mDurationMs));
+            out.attribute(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION,
+                    String.valueOf(mHealthCheckDurationMs));
+            out.attribute(null, ATTR_PASSED_HEALTH_CHECK,
+                    String.valueOf(mHasPassedHealthCheck));
+            out.endTag(null, TAG_PACKAGE);
         }
 
         /**
@@ -929,7 +927,7 @@
          * @return {@code true} if failure count exceeds a threshold, {@code false} otherwise
          */
         @GuardedBy("mLock")
-        public boolean onFailure() {
+        public boolean onFailureLocked() {
             final long now = SystemClock.uptimeMillis();
             final long duration = now - mUptimeStartMs;
             if (duration > TRIGGER_DURATION_MS) {
@@ -949,18 +947,141 @@
         }
 
         /**
-         * Returns any of the health check states of {@link #STATE_ACTIVE},
+         * Sets the initial health check duration.
+         *
+         * @return the new health check state
+         */
+        @GuardedBy("mLock")
+        public int setHealthCheckActiveLocked(long initialHealthCheckDurationMs) {
+            if (initialHealthCheckDurationMs <= 0) {
+                Slog.wtf(TAG, "Cannot set non-positive health check duration "
+                        + initialHealthCheckDurationMs + "ms for package " + mName
+                        + ". Using total duration " + mDurationMs + "ms instead");
+                initialHealthCheckDurationMs = mDurationMs;
+            }
+            if (mHealthCheckState == STATE_INACTIVE) {
+                // Transitions to ACTIVE
+                mHealthCheckDurationMs = initialHealthCheckDurationMs;
+            }
+            return updateHealthCheckStateLocked();
+        }
+
+        /**
+         * Updates the monitoring durations of the package.
+         *
+         * @return the new health check state
+         */
+        @GuardedBy("mLock")
+        public int handleElapsedTimeLocked(long elapsedMs) {
+            if (elapsedMs <= 0) {
+                Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + mName);
+                return mHealthCheckState;
+            }
+            // Transitions to FAILED if now <= 0 and health check not passed
+            mDurationMs -= elapsedMs;
+            if (mHealthCheckState == STATE_ACTIVE) {
+                // We only update health check durations if we have #setHealthCheckActiveLocked
+                // This ensures we don't leave the INACTIVE state for an unexpected elapsed time
+                // Transitions to FAILED if now <= 0 and health check not passed
+                mHealthCheckDurationMs -= elapsedMs;
+            }
+            return updateHealthCheckStateLocked();
+        }
+
+        /**
+         * Marks the health check as passed and transitions to {@link #STATE_PASSED}
+         * if not yet {@link #STATE_FAILED}.
+         *
+         * @return the new health check state
+         */
+        @GuardedBy("mLock")
+        public int tryPassHealthCheckLocked() {
+            if (mHealthCheckState != STATE_FAILED) {
+                // FAILED is a final state so only pass if we haven't failed
+                // Transition to PASSED
+                mHasPassedHealthCheck = true;
+            }
+            return updateHealthCheckStateLocked();
+        }
+
+        /** Returns the monitored package name. */
+        private String getName() {
+            return mName;
+        }
+
+        //TODO(b/120598832): IntDef
+        /**
+         * Returns the current health check state, any of {@link #STATE_ACTIVE},
          * {@link #STATE_INACTIVE} or {@link #STATE_PASSED}
          */
         @GuardedBy("mLock")
-        public int getHealthCheckState() {
+        public int getHealthCheckStateLocked() {
+            return mHealthCheckState;
+        }
+
+        /**
+         * Returns the shortest duration before the package should be scheduled for a prune.
+         *
+         * @return the duration or {@link Long#MAX_VALUE} if the package should not be scheduled
+         */
+        @GuardedBy("mLock")
+        public long getShortestScheduleDurationMsLocked() {
+            return Math.min(toPositive(mDurationMs), toPositive(mHealthCheckDurationMs));
+        }
+
+        /**
+         * Returns {@code true} if the total duration left to monitor the package is less than or
+         * equal to 0 {@code false} otherwise.
+         */
+        @GuardedBy("mLock")
+        public boolean isExpiredLocked() {
+            return mDurationMs <= 0;
+        }
+
+        /**
+         * Updates the health check state based on {@link #mHasPassedHealthCheck}
+         * and {@link #mHealthCheckDurationMs}.
+         *
+         * @return the new health check state
+         */
+        @GuardedBy("mLock")
+        private int updateHealthCheckStateLocked() {
+            int oldState = mHealthCheckState;
             if (mHasPassedHealthCheck) {
-                return STATE_PASSED;
+                // Set final state first to avoid ambiguity
+                mHealthCheckState = STATE_PASSED;
+            } else if (mHealthCheckDurationMs <= 0 || mDurationMs <= 0) {
+                // Set final state first to avoid ambiguity
+                mHealthCheckState = STATE_FAILED;
             } else if (mHealthCheckDurationMs == Long.MAX_VALUE) {
-                return STATE_INACTIVE;
+                mHealthCheckState = STATE_INACTIVE;
             } else {
-                return STATE_ACTIVE;
+                mHealthCheckState = STATE_ACTIVE;
             }
+            Slog.i(TAG, "Updated health check state for package " + mName + ": "
+                    + toString(oldState) + " -> " + toString(mHealthCheckState));
+            return mHealthCheckState;
+        }
+
+        /** Returns a {@link String} representation of the current health check state. */
+        private static String toString(int state) {
+            switch (state) {
+                case STATE_ACTIVE:
+                    return "ACTIVE";
+                case STATE_INACTIVE:
+                    return "INACTIVE";
+                case STATE_PASSED:
+                    return "PASSED";
+                case STATE_FAILED:
+                    return "FAILED";
+                default:
+                    return "UNKNOWN";
+            }
+        }
+
+        /** Returns {@code value} if it is greater than 0 or {@link Long#MAX_VALUE} otherwise. */
+        private static long toPositive(long value) {
+            return value > 0 ? value : Long.MAX_VALUE;
         }
     }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 0786b18..da9cffa 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3836,9 +3836,9 @@
             }
 
             // Determine if caller is holding runtime permission
-            final boolean hasRead = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
+            final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
                     uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
-            final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
+            final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
                     uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
             // STOPSHIP: remove this temporary hack once we have dynamic runtime
             // permissions fully enabled again
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 5cc9bfd..6bb3200 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -22,9 +22,10 @@
 
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.Preconditions;
+import com.android.server.am.ActivityManagerService;
 
+import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -47,6 +48,8 @@
     private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(4,
             "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
 
+    private List<String> mPendingTasks = new ArrayList<>();
+
     public static synchronized SystemServerInitThreadPool get() {
         if (sInstance == null) {
             sInstance = new SystemServerInitThreadPool();
@@ -57,19 +60,26 @@
     }
 
     public Future<?> submit(Runnable runnable, String description) {
-        if (IS_DEBUGGABLE) {
-            return mService.submit(() -> {
-                Slog.d(TAG, "Started executing " + description);
-                try {
-                    runnable.run();
-                } catch (RuntimeException e) {
-                    Slog.e(TAG, "Failure in " + description + ": " + e, e);
-                    throw e;
-                }
-                Slog.d(TAG, "Finished executing "  + description);
-            });
+        synchronized (mPendingTasks) {
+            mPendingTasks.add(description);
         }
-        return mService.submit(runnable);
+        return mService.submit(() -> {
+            if (IS_DEBUGGABLE) {
+                Slog.d(TAG, "Started executing " + description);
+            }
+            try {
+                runnable.run();
+            } catch (RuntimeException e) {
+                Slog.e(TAG, "Failure in " + description + ": " + e, e);
+                throw e;
+            }
+            synchronized (mPendingTasks) {
+                mPendingTasks.remove(description);
+            }
+            if (IS_DEBUGGABLE) {
+                Slog.d(TAG, "Finished executing " + description);
+            }
+        });
     }
 
     static synchronized void shutdown() {
@@ -81,16 +91,36 @@
                         TimeUnit.MILLISECONDS);
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
+                dumpStackTraces();
                 throw new IllegalStateException(TAG + " init interrupted");
             }
+            if (!terminated) {
+                // dump stack must be called before shutdownNow() to collect stacktrace of threads
+                // in the thread pool.
+                dumpStackTraces();
+            }
             List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow();
             if (!terminated) {
+                final List<String> copy = new ArrayList<>();
+                synchronized (sInstance.mPendingTasks) {
+                    copy.addAll(sInstance.mPendingTasks);
+                }
                 throw new IllegalStateException("Cannot shutdown. Unstarted tasks "
-                        + unstartedRunnables);
+                        + unstartedRunnables + " Unfinished tasks " + copy);
             }
             sInstance.mService = null; // Make mService eligible for GC
+            sInstance.mPendingTasks = null;
             Slog.d(TAG, "Shutdown successful");
         }
     }
 
+    /**
+     * A helper function to call ActivityManagerService.dumpStackTraces().
+     */
+    private static void dumpStackTraces() {
+        final ArrayList<Integer> pids = new ArrayList<>();
+        pids.add(Process.myPid());
+        ActivityManagerService.dumpStackTraces(
+                pids, null, null, null);
+    }
 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c647e2e..af78b76 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1172,7 +1172,11 @@
                     .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i))
                     .findFirst().getAsInt();
         } catch (NoSuchElementException ex) {
-            log("notifyCarrierNetworkChange without carrier privilege");
+            loge("notifyCarrierNetworkChange without carrier privilege");
+        }
+        // the active subId does not have carrier privilege. 
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            throw new SecurityException("notifyCarrierNetworkChange without carrier privilege");
         }
         int phoneId = SubscriptionManager.getPhoneId(subId);
 
@@ -1304,12 +1308,12 @@
             return;
         }
         if (VDBG) {
-            log("notifyUserMobileDataStateChangedForSubscriberPhoneID: subId=" + phoneId
-                    + " state=" + state);
+            log("notifyUserMobileDataStateChangedForSubscriberPhoneID: PhoneId=" + phoneId
+                    + " subId=" + subId + " state=" + state);
         }
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
-                mMessageWaiting[phoneId] = state;
+                mUserMobileDataState[phoneId] = state;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
                             PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) &&
@@ -2272,6 +2276,10 @@
         Rlog.d(TAG, s);
     }
 
+    private static void loge(String s) {
+        Rlog.e(TAG, s);
+    }
+
     boolean idMatch(int rSubId, int subId, int phoneId) {
 
         if(subId < 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1757c98..0b9e3bb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6147,8 +6147,9 @@
     }
 
     @Override
-    public void moveTaskToFront(int taskId, int flags, Bundle bOptions) {
-        mActivityTaskManager.moveTaskToFront(taskId, flags, bOptions);
+    public void moveTaskToFront(IApplicationThread appThread, String callingPackage, int taskId,
+            int flags, Bundle bOptions) {
+        mActivityTaskManager.moveTaskToFront(appThread, callingPackage, taskId, flags, bOptions);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 5d47c9d..44d435f 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1262,15 +1262,16 @@
                                 // processes).  These should not bring the current process
                                 // into the top state, since they are not on top.  Instead
                                 // give them the best bound state after that.
+                                final int bestState = cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)
+                                        ? PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
+                                        : PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                                 if ((cr.flags & Context.BIND_FOREGROUND_SERVICE) != 0) {
-                                    clientProcState =
-                                            PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                                    clientProcState = bestState;
                                 } else if (mService.mWakefulness
                                         == PowerManagerInternal.WAKEFULNESS_AWAKE
                                         && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
                                                 != 0) {
-                                    clientProcState =
-                                            PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                                    clientProcState = bestState;
                                 } else {
                                     clientProcState =
                                             PROCESS_STATE_IMPORTANT_FOREGROUND;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 8847e32..01a3a6f 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1020,11 +1020,7 @@
                         if (state.state == STATE_RUNNING_UNLOCKED) {
                             // We'll skip all later code, so we must tell listener it's already
                             // unlocked.
-                            try {
-                                unlockListener.onFinished(userId, null);
-                            } catch (RemoteException ignore) {
-                                // Ignore.
-                            }
+                            notifyFinished(userId, unlockListener);
                         }
                         return true;
                     }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index d073bc6..4c3bb8c 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1840,11 +1840,14 @@
     }
 
     private boolean isPackageSuspendedForUser(String pkg, int uid) {
+        final long identity = Binder.clearCallingIdentity();
         try {
             return AppGlobals.getPackageManager().isPackageSuspendedForUser(
                     pkg, UserHandle.getUserId(uid));
         } catch (RemoteException re) {
             throw new SecurityException("Could not talk to package manager service");
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index bc78d1a..3dbea0d 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -22,7 +22,6 @@
 import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN;
 
 import android.Manifest;
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
@@ -51,6 +50,7 @@
 import android.provider.Settings;
 import android.service.attention.AttentionService;
 import android.service.attention.AttentionService.AttentionFailureCodes;
+import android.service.attention.AttentionService.AttentionSuccessCodes;
 import android.service.attention.IAttentionCallback;
 import android.service.attention.IAttentionService;
 import android.text.TextUtils;
@@ -75,6 +75,7 @@
  */
 public class AttentionManagerService extends SystemService {
     private static final String LOG_TAG = "AttentionManagerService";
+    private static final boolean DEBUG = false;
 
     /**
      * DeviceConfig flag name, allows a CTS to inject a fake implementation.
@@ -156,7 +157,11 @@
     /**
      * Checks whether user attention is at the screen and calls in the provided callback.
      *
-     * @return {@code true} if the framework was able to send the provided callback to the service
+     * Calling this multiple times quickly in a row will result in either a) returning a cached
+     * value, if present, or b) returning {@code false} because only one active request at a time is
+     * allowed.
+     *
+     * @return {@code true} if the framework was able to dispatch the request
      */
     private boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
         Preconditions.checkNotNull(callbackInternal);
@@ -182,54 +187,30 @@
                 return false;
             }
 
-            if (userState.mService == null) {
-                // make sure every callback is called back
-                if (userState.mPendingAttentionCheck != null) {
-                    userState.mPendingAttentionCheck.cancel(
-                            ATTENTION_FAILURE_CANCELLED);
-                }
-                // fire the check when the service is started
-                userState.mPendingAttentionCheck = new PendingAttentionCheck(
-                        callbackInternal, () -> checkAttention(timeout, callbackInternal));
-            } else {
-                try {
-                    // throttle frequent requests
-                    final AttentionCheckCache cache = userState.mAttentionCheckCache;
-                    if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) {
-                        callbackInternal.onSuccess(cache.mResult, cache.mTimestamp);
-                        return true;
-                    }
+            // throttle frequent requests
+            final AttentionCheckCache cache = userState.mAttentionCheckCache;
+            if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) {
+                callbackInternal.onSuccess(cache.mResult, cache.mTimestamp);
+                return true;
+            }
 
+            // prevent spamming with multiple requests, only one at a time is allowed
+            if (userState.mCurrentAttentionCheck != null) {
+                if (!userState.mCurrentAttentionCheck.mIsDispatched
+                        || !userState.mCurrentAttentionCheck.mIsFulfilled) {
+                    return false;
+                }
+            }
+
+            userState.mCurrentAttentionCheck = createAttentionCheck(callbackInternal, userState);
+
+            if (userState.mService != null) {
+                try {
                     // schedule request cancellation if not returned by that point yet
                     cancelAfterTimeoutLocked(timeout);
-
-                    userState.mCurrentAttentionCheck = new AttentionCheck(callbackInternal,
-                            new IAttentionCallback.Stub() {
-                                @Override
-                                public void onSuccess(int result, long timestamp) {
-                                    callbackInternal.onSuccess(result, timestamp);
-                                    synchronized (mLock) {
-                                        userState.mAttentionCheckCache = new AttentionCheckCache(
-                                                SystemClock.uptimeMillis(), result,
-                                                timestamp);
-                                        userState.mCurrentAttentionCheckIsFulfilled = true;
-                                    }
-                                    StatsLog.write(
-                                            StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
-                                            result);
-                                }
-
-                                @Override
-                                public void onFailure(int error) {
-                                    callbackInternal.onFailure(error);
-                                    userState.mCurrentAttentionCheckIsFulfilled = true;
-                                    StatsLog.write(
-                                            StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
-                                            error);
-                                }
-                            });
                     userState.mService.checkAttention(
                             userState.mCurrentAttentionCheck.mIAttentionCallback);
+                    userState.mCurrentAttentionCheck.mIsDispatched = true;
                 } catch (RemoteException e) {
                     Slog.e(LOG_TAG, "Cannot call into the AttentionService");
                     return false;
@@ -239,6 +220,44 @@
         }
     }
 
+    private AttentionCheck createAttentionCheck(AttentionCallbackInternal callbackInternal,
+            UserState userState) {
+        final IAttentionCallback iAttentionCallback = new IAttentionCallback.Stub() {
+            @Override
+            public void onSuccess(@AttentionSuccessCodes int result, long timestamp) {
+                // the callback might have been cancelled already
+                if (!userState.mCurrentAttentionCheck.mIsFulfilled) {
+                    callbackInternal.onSuccess(result, timestamp);
+                    userState.mCurrentAttentionCheck.mIsFulfilled = true;
+                }
+
+                synchronized (mLock) {
+                    userState.mAttentionCheckCache = new AttentionCheckCache(
+                            SystemClock.uptimeMillis(), result,
+                            timestamp);
+                }
+                StatsLog.write(
+                        StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
+                        result);
+            }
+
+            @Override
+            public void onFailure(@AttentionFailureCodes int error) {
+                // the callback might have been cancelled already
+                if (!userState.mCurrentAttentionCheck.mIsFulfilled) {
+                    callbackInternal.onFailure(error);
+                    userState.mCurrentAttentionCheck.mIsFulfilled = true;
+                }
+
+                StatsLog.write(
+                        StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
+                        error);
+            }
+        };
+
+        return new AttentionCheck(callbackInternal, iAttentionCallback);
+    }
+
     /** Cancels the specified attention check. */
     private void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
         synchronized (mLock) {
@@ -246,25 +265,13 @@
             if (userState == null) {
                 return;
             }
-            if (userState.mService == null) {
-                if (userState.mPendingAttentionCheck != null
-                        && userState.mPendingAttentionCheck.mCallbackInternal.equals(
-                        callbackInternal)) {
-                    userState.mPendingAttentionCheck.cancel(ATTENTION_FAILURE_UNKNOWN);
-                    userState.mPendingAttentionCheck = null;
-                }
+
+            if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) {
+                Slog.e(LOG_TAG, "Cannot cancel a non-current request");
                 return;
             }
-            if (userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) {
-                try {
-                    userState.mService.cancelAttentionCheck(
-                            userState.mCurrentAttentionCheck.mIAttentionCallback);
-                } catch (RemoteException e) {
-                    Slog.e(LOG_TAG, "Cannot call into the AttentionService");
-                }
-            } else {
-                Slog.e(LOG_TAG, "Cannot cancel a non-current request");
-            }
+
+            cancel(userState);
         }
     }
 
@@ -272,6 +279,9 @@
     private void disableSelf() {
         final long identity = Binder.clearCallingIdentity();
         try {
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "Disabling self.");
+            }
             Settings.System.putInt(mContext.getContentResolver(), ADAPTIVE_SLEEP, 0);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -428,34 +438,21 @@
         }
     }
 
-    private static final class PendingAttentionCheck {
-        private final AttentionCallbackInternal mCallbackInternal;
-        private final Runnable mRunnable;
-
-        PendingAttentionCheck(AttentionCallbackInternal callbackInternal,
-                Runnable runnable) {
-            mCallbackInternal = callbackInternal;
-            mRunnable = runnable;
-        }
-
-        void cancel(@AttentionFailureCodes int failureCode) {
-            mCallbackInternal.onFailure(failureCode);
-        }
-
-        void run() {
-            mRunnable.run();
-        }
-    }
-
     private static final class AttentionCheck {
         private final AttentionCallbackInternal mCallbackInternal;
         private final IAttentionCallback mIAttentionCallback;
+        private boolean mIsDispatched;
+        private boolean mIsFulfilled;
 
         AttentionCheck(AttentionCallbackInternal callbackInternal,
                 IAttentionCallback iAttentionCallback) {
             mCallbackInternal = callbackInternal;
             mIAttentionCallback = iAttentionCallback;
         }
+
+        void cancelInternal() {
+            mCallbackInternal.onFailure(ATTENTION_FAILURE_CANCELLED);
+        }
     }
 
     private static final class UserState {
@@ -469,11 +466,6 @@
         @GuardedBy("mLock")
         AttentionCheck mCurrentAttentionCheck;
         @GuardedBy("mLock")
-        boolean mCurrentAttentionCheckIsFulfilled;
-
-        @GuardedBy("mLock")
-        PendingAttentionCheck mPendingAttentionCheck;
-        @GuardedBy("mLock")
         AttentionCheckCache mAttentionCheckCache;
 
         @UserIdInt
@@ -491,9 +483,17 @@
 
         @GuardedBy("mLock")
         private void handlePendingCallbackLocked() {
-            if (mService != null && mPendingAttentionCheck != null) {
-                mPendingAttentionCheck.run();
-                mPendingAttentionCheck = null;
+            if (!mCurrentAttentionCheck.mIsDispatched) {
+                if (mService != null) {
+                    try {
+                        mService.checkAttention(mCurrentAttentionCheck.mIAttentionCallback);
+                        mCurrentAttentionCheck.mIsDispatched = true;
+                    } catch (RemoteException e) {
+                        Slog.e(LOG_TAG, "Cannot call into the AttentionService");
+                    }
+                } else {
+                    mCurrentAttentionCheck.mCallbackInternal.onFailure(ATTENTION_FAILURE_UNKNOWN);
+                }
             }
         }
 
@@ -526,7 +526,6 @@
             pw.printPair("userId", mUserId);
             synchronized (mLock) {
                 pw.printPair("binding", mBinding);
-                pw.printPair("isAttentionCheckPending", mPendingAttentionCheck != null);
             }
         }
 
@@ -586,14 +585,7 @@
                 // Callee is no longer interested in the attention check result - cancel.
                 case ATTENTION_CHECK_TIMEOUT: {
                     synchronized (mLock) {
-                        final UserState userState = peekCurrentUserStateLocked();
-                        if (userState != null) {
-                            // If not called back already.
-                            if (!userState.mCurrentAttentionCheckIsFulfilled) {
-                                cancel(userState, AttentionService.ATTENTION_FAILURE_TIMED_OUT);
-                            }
-
-                        }
+                        cancel(peekCurrentUserStateLocked());
                     }
                 }
                 break;
@@ -604,19 +596,30 @@
         }
     }
 
-    private void cancel(@NonNull UserState userState, @AttentionFailureCodes int failureCode) {
-        if (userState.mService != null) {
-            try {
-                userState.mService.cancelAttentionCheck(
-                        userState.mCurrentAttentionCheck.mIAttentionCallback);
-            } catch (RemoteException e) {
-                Slog.e(LOG_TAG, "Unable to cancel attention check");
-            }
+    private void cancel(UserState userState) {
+        if (userState == null || userState.mCurrentAttentionCheck == null) {
+            return;
+        }
 
-            if (userState.mPendingAttentionCheck != null) {
-                userState.mPendingAttentionCheck.cancel(failureCode);
-                userState.mPendingAttentionCheck = null;
+        if (userState.mCurrentAttentionCheck.mIsFulfilled) {
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "Trying to cancel the check that has been already fulfilled.");
             }
+            return;
+        }
+        userState.mCurrentAttentionCheck.mIsFulfilled = true;
+
+        if (userState.mService == null) {
+            userState.mCurrentAttentionCheck.cancelInternal();
+            return;
+        }
+
+        try {
+            userState.mService.cancelAttentionCheck(
+                    userState.mCurrentAttentionCheck.mIAttentionCallback);
+        } catch (RemoteException e) {
+            Slog.e(LOG_TAG, "Unable to cancel attention check");
+            userState.mCurrentAttentionCheck.cancelInternal();
         }
     }
 
@@ -626,7 +629,12 @@
             if (userState == null) {
                 return;
             }
-            cancel(userState, ATTENTION_FAILURE_UNKNOWN);
+
+            cancel(userState);
+
+            if (userState.mService == null) {
+                return;
+            }
 
             mContext.unbindService(userState.mConnection);
             userState.mConnection.cleanupService();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 32781a9..d58888a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -855,8 +855,7 @@
 
     public void onSystemReady() {
         mSystemReady = true;
-        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
-                0, 0, null, 0);
+        scheduleLoadSoundEffects();
 
         mDeviceBroker.onSystemReady();
 
@@ -1961,7 +1960,7 @@
             return;
         }
         for (final int groupedStream : avg.getLegacyStreamTypes()) {
-            setStreamVolume(stream, index, flags, callingPackage, callingPackage,
+            setStreamVolume(groupedStream, index, flags, callingPackage, callingPackage,
                             Binder.getCallingUid());
         }
     }
@@ -3225,6 +3224,14 @@
     }
 
     /**
+     * Schedule loading samples into the soundpool.
+     * This method can be overridden to schedule loading at a later time.
+     */
+    protected void scheduleLoadSoundEffects() {
+        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
+    }
+
+    /**
      *  Unloads samples from the sound pool.
      *  This method can be called to free some memory when
      *  sound effects are disabled.
@@ -3361,8 +3368,14 @@
                 .append(Binder.getCallingPid()).toString();
         final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
         if (stateChanged) {
-            mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
-                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mContext.sendBroadcastAsUser(
+                        new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+                                .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 7d4ac59..f7278d2 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -129,13 +129,16 @@
         boolean result = false;
 
         try {
+            if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + authenticated + ")"
+                    + ", ID:" + identifier.getBiometricId()
+                    + ", Owner: " + getOwnerString()
+                    + ", isBP: " + isBiometricPrompt()
+                    + ", listener: " + listener
+                    + ", requireConfirmation: " + mRequireConfirmation);
+
             if (authenticated) {
                 mAlreadyDone = true;
-                if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + getOwnerString()
-                        + ", ID:" + identifier.getBiometricId()
-                        + ", isBP: " + isBiometricPrompt()
-                        + ", listener: " + listener
-                        + ", requireConfirmation: " + mRequireConfirmation);
+
                 if (listener != null) {
                     vibrateSuccess();
                 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 843ecac..153133a 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -41,6 +41,7 @@
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -85,6 +86,7 @@
 public class BiometricService extends SystemService {
 
     private static final String TAG = "BiometricService";
+    private static final boolean DEBUG = true;
 
     private static final int MSG_ON_TASK_STACK_CHANGED = 1;
     private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
@@ -96,6 +98,9 @@
     private static final int MSG_ON_READY_FOR_AUTHENTICATION = 8;
     private static final int MSG_AUTHENTICATE = 9;
     private static final int MSG_CANCEL_AUTHENTICATION = 10;
+    private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11;
+    private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12;
+    private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13;
 
     private static final int[] FEATURE_ID = {
         TYPE_FINGERPRINT,
@@ -128,8 +133,12 @@
      * Authentication is successful, but we're waiting for the user to press "confirm" button.
      */
     private static final int STATE_AUTH_PENDING_CONFIRM = 5;
+    /**
+     * Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential
+     */
+    private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6;
 
-    private final class AuthSession {
+    private final class AuthSession implements IBinder.DeathRecipient {
         // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
         // <Biometric>Services before we can start authenticating. Pairs that have been returned
         // are moved to mModalitiesMatched.
@@ -164,10 +173,14 @@
         // Timestamp when hardware authentication occurred
         private long mAuthenticatedTimeMs;
 
+        // TODO(b/123378871): Remove when moved.
+        private IBiometricConfirmDeviceCredentialCallback mConfirmDeviceCredentialCallback;
+
         AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
                 int userId, IBiometricServiceReceiver receiver, String opPackageName,
                 Bundle bundle, int callingUid, int callingPid, int callingUserId,
-                int modality, boolean requireConfirmation) {
+                int modality, boolean requireConfirmation,
+                IBiometricConfirmDeviceCredentialCallback callback) {
             mModalitiesWaiting = modalities;
             mToken = token;
             mSessionId = sessionId;
@@ -180,12 +193,25 @@
             mCallingUserId = callingUserId;
             mModality = modality;
             mRequireConfirmation = requireConfirmation;
+            mConfirmDeviceCredentialCallback = callback;
+
+            if (isFromConfirmDeviceCredential()) {
+                try {
+                    token.linkToDeath(this, 0 /* flags */);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to link to death", e);
+                }
+            }
         }
 
         boolean isCrypto() {
             return mSessionId != 0;
         }
 
+        boolean isFromConfirmDeviceCredential() {
+            return mBundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
+        }
+
         boolean containsCookie(int cookie) {
             if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) {
                 return true;
@@ -195,6 +221,25 @@
             }
             return false;
         }
+
+        // TODO(b/123378871): Remove when moved.
+        @Override
+        public void binderDied() {
+            mHandler.post(() -> {
+                Slog.e(TAG, "Binder died, killing ConfirmDeviceCredential");
+                if (mConfirmDeviceCredentialCallback == null) {
+                    Slog.e(TAG, "Callback is null");
+                    return;
+                }
+
+                try {
+                    mConfirmDeviceCredentialCallback.cancel();
+                    mConfirmDeviceCredentialCallback = null;
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to send cancel", e);
+                }
+            });
+        }
     }
 
     private final class BiometricTaskStackListener extends TaskStackListener {
@@ -234,6 +279,14 @@
     private AuthSession mCurrentAuthSession;
     private AuthSession mPendingAuthSession;
 
+    // TODO(b/123378871): Remove when moved.
+    // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
+    // client (app) receiver. BiometricService internally launches CDCA which invokes
+    // BiometricService to start authentication (normal path). When auth is success/rejected,
+    // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
+    // to this receiver.
+    private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
+
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
@@ -311,7 +364,8 @@
                             (Bundle) args.arg5 /* bundle */,
                             args.argi2 /* callingUid */,
                             args.argi3 /* callingPid */,
-                            args.argi4 /* callingUserId */);
+                            args.argi4 /* callingUserId */,
+                            (IBiometricConfirmDeviceCredentialCallback) args.arg6 /* callback */);
                     args.recycle();
                     break;
                 }
@@ -325,7 +379,28 @@
                     break;
                 }
 
+                case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS: {
+                    handleOnConfirmDeviceCredentialSuccess();
+                    break;
+                }
+
+                case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleOnConfirmDeviceCredentialError(
+                            args.argi1 /* error */,
+                            (String) args.arg1 /* errorMsg */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_REGISTER_CANCELLATION_CALLBACK: {
+                    handleRegisterCancellationCallback(
+                            (IBiometricConfirmDeviceCredentialCallback) msg.obj /* callback */);
+                    break;
+                }
+
                 default:
+                    Slog.e(TAG, "Unknown message: " + msg);
                     break;
             }
         }
@@ -533,14 +608,6 @@
      * cancelAuthentication() can go to the right place.
      */
     private final class BiometricServiceWrapper extends IBiometricService.Stub {
-        // TODO(b/123378871): Remove when moved.
-        // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
-        // client (app) receiver. BiometricService internally launches CDCA which invokes
-        // BiometricService to start authentication (normal path). When auth is success/rejected,
-        // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
-        // to this receiver.
-        private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
-
         @Override // Binder call
         public void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId) {
             checkInternalPermission();
@@ -554,12 +621,18 @@
 
         @Override // Binder call
         public void authenticate(IBinder token, long sessionId, int userId,
-                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle)
+                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
+                IBiometricConfirmDeviceCredentialCallback callback)
                 throws RemoteException {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
 
+            // TODO(b/123378871): Remove when moved.
+            if (callback != null) {
+                checkInternalPermission();
+            }
+
             // In the BiometricServiceBase, check do the AppOps and foreground check.
             if (userId == callingUserId) {
                 // Check the USE_BIOMETRIC permission here.
@@ -576,6 +649,12 @@
                 return;
             }
 
+            final boolean isFromConfirmDeviceCredential =
+                    bundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
+            if (isFromConfirmDeviceCredential) {
+                checkInternalPermission();
+            }
+
             // Check the usage of this in system server. Need to remove this check if it becomes
             // a public API.
             final boolean useDefaultTitle =
@@ -632,6 +711,7 @@
             args.argi2 = callingUid;
             args.argi3 = callingPid;
             args.argi4 = callingUserId;
+            args.arg6 = callback;
 
             mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
         }
@@ -639,35 +719,30 @@
         @Override // Binder call
         public void onConfirmDeviceCredentialSuccess() {
             checkInternalPermission();
-            mHandler.post(() -> {
-                if (mConfirmDeviceCredentialReceiver == null) {
-                    Slog.w(TAG, "onCDCASuccess null!");
-                    return;
-                }
-                try {
-                    mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "RemoteException", e);
-                }
-                mConfirmDeviceCredentialReceiver = null;
-            });
+
+            mHandler.sendEmptyMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS);
         }
 
         @Override // Binder call
         public void onConfirmDeviceCredentialError(int error, String message) {
             checkInternalPermission();
-            mHandler.post(() -> {
-                if (mConfirmDeviceCredentialReceiver == null) {
-                    Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
-                    return;
-                }
-                try {
-                    mConfirmDeviceCredentialReceiver.onError(error, message);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "RemoteException", e);
-                }
-                mConfirmDeviceCredentialReceiver = null;
-            });
+
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = error;
+            args.arg1 = message;
+            mHandler.obtainMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR, args).sendToTarget();
+        }
+
+        @Override // Binder call
+        public void registerCancellationCallback(
+                IBiometricConfirmDeviceCredentialCallback callback) {
+            // TODO(b/123378871): Remove when moved.
+            // This callback replaces the one stored in the current session. If the session is null
+            // we can ignore this, since it means ConfirmDeviceCredential was launched by something
+            // else (not BiometricPrompt)
+            checkInternalPermission();
+
+            mHandler.obtainMessage(MSG_REGISTER_CANCELLATION_CALLBACK, callback).sendToTarget();
         }
 
         @Override // Binder call
@@ -1104,6 +1179,52 @@
         }
     }
 
+    private void handleOnConfirmDeviceCredentialSuccess() {
+        if (mConfirmDeviceCredentialReceiver == null) {
+            Slog.w(TAG, "onCDCASuccess null!");
+            return;
+        }
+        try {
+            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+            mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
+            if (mCurrentAuthSession != null) {
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException", e);
+        }
+        mConfirmDeviceCredentialReceiver = null;
+    }
+
+    private void handleOnConfirmDeviceCredentialError(int error, String message) {
+        if (mConfirmDeviceCredentialReceiver == null) {
+            Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+            return;
+        }
+        try {
+            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+            mConfirmDeviceCredentialReceiver.onError(error, message);
+            if (mCurrentAuthSession != null) {
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException", e);
+        }
+        mConfirmDeviceCredentialReceiver = null;
+    }
+
+    private void handleRegisterCancellationCallback(
+            IBiometricConfirmDeviceCredentialCallback callback) {
+        if (mCurrentAuthSession == null) {
+            Slog.d(TAG, "Current auth session null");
+            return;
+        }
+        Slog.d(TAG, "Updating cancel callback");
+        mCurrentAuthSession.mConfirmDeviceCredentialCallback = callback;
+    }
+
     private void handleOnError(int cookie, int error, String message) {
         Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
         // Errors can either be from the current auth session or the pending auth session.
@@ -1114,7 +1235,18 @@
         // of their intended receivers.
         try {
             if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
-                if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
+
+                if (mCurrentAuthSession.isFromConfirmDeviceCredential()) {
+                    // If we were invoked by ConfirmDeviceCredential, do not delete the current
+                    // auth session since we still need to respond to cancel signal while
+                    if (DEBUG) Slog.d(TAG, "From CDC, transition to CANCELED_SHOWING_CDC state");
+
+                    // Send the error to ConfirmDeviceCredential so that it goes to Pin/Pattern/Pass
+                    // screen
+                    mCurrentAuthSession.mClientReceiver.onError(error, message);
+                    mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC;
+                    mStatusBarService.hideBiometricDialog();
+                } else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
                     mStatusBarService.onBiometricError(message);
                     if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
                         mActivityTaskManager.unregisterTaskStackListener(
@@ -1214,9 +1346,16 @@
                 KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
                 mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
             }
-            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-            mCurrentAuthSession = null;
+
+            // Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the
+            // STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when
+            // ConfirmDeviceCredential is confirmed or canceled.
+            // TODO(b/123378871): Remove when moved
+            if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) {
+                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+            }
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception", e);
         }
@@ -1235,7 +1374,8 @@
                 mCurrentAuthSession.mCallingUid,
                 mCurrentAuthSession.mCallingPid,
                 mCurrentAuthSession.mCallingUserId,
-                mCurrentAuthSession.mModality);
+                mCurrentAuthSession.mModality,
+                mCurrentAuthSession.mConfirmDeviceCredentialCallback);
     }
 
     private void handleOnReadyForAuthentication(int cookie, boolean requireConfirmation,
@@ -1290,7 +1430,8 @@
 
     private void handleAuthenticate(IBinder token, long sessionId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
-            int callingUid, int callingPid, int callingUserId) {
+            int callingUid, int callingPid, int callingUserId,
+            IBiometricConfirmDeviceCredentialCallback callback) {
 
         mHandler.post(() -> {
             final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
@@ -1328,7 +1469,7 @@
             // Start preparing for authentication. Authentication starts when
             // all modalities requested have invoked onReadyForAuthentication.
             authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
-                    callingUid, callingPid, callingUserId, modality);
+                    callingUid, callingPid, callingUserId, modality, callback);
         });
     }
 
@@ -1343,7 +1484,8 @@
      */
     private void authenticateInternal(IBinder token, long sessionId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
-            int callingUid, int callingPid, int callingUserId, int modality) {
+            int callingUid, int callingPid, int callingUserId, int modality,
+            IBiometricConfirmDeviceCredentialCallback callback) {
         try {
             boolean requireConfirmation = bundle.getBoolean(
                     BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
@@ -1363,7 +1505,7 @@
             authenticators.put(modality, cookie);
             mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
                     receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
-                    modality, requireConfirmation);
+                    modality, requireConfirmation, callback);
             mPendingAuthSession.mState = STATE_AUTH_CALLED;
             // No polymorphism :(
             if ((modality & TYPE_FINGERPRINT) != 0) {
@@ -1390,10 +1532,23 @@
             return;
         }
 
-        // We need to check the current authenticators state. If we're pending confirm
-        // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
-        // since we won't be getting an onError from the driver.
-        if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+        if (mCurrentAuthSession != null
+                && mCurrentAuthSession.mState == STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC) {
+            if (DEBUG) Slog.d(TAG, "Cancel received while ConfirmDeviceCredential showing");
+            try {
+                mCurrentAuthSession.mConfirmDeviceCredentialCallback.cancel();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to cancel ConfirmDeviceCredential", e);
+            }
+
+            // TODO(b/123378871): Remove when moved. Piggy back on this for now to clean up.
+            handleOnConfirmDeviceCredentialError(BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+                    getContext().getString(R.string.biometric_error_canceled));
+        } else if (mCurrentAuthSession != null
+                && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+            // We need to check the current authenticators state. If we're pending confirm
+            // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
+            // since we won't be getting an onError from the driver.
             try {
                 // Send error to client
                 mCurrentAuthSession.mClientReceiver.onError(
@@ -1409,11 +1564,22 @@
                 Slog.e(TAG, "Remote exception", e);
             }
         } else {
-            cancelInternal(token, opPackageName, true /* fromClient */);
+            boolean fromCDC = false;
+            if (mCurrentAuthSession != null) {
+                fromCDC = mCurrentAuthSession.mBundle.getBoolean(
+                        BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
+            }
+
+            if (fromCDC) {
+                if (DEBUG) Slog.d(TAG, "Cancelling from CDC");
+                cancelInternal(token, opPackageName, false /* fromClient */);
+            } else {
+                cancelInternal(token, opPackageName, true /* fromClient */);
+            }
+
         }
     }
 
-
     void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 527539d..7733d67 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -50,7 +50,7 @@
 import java.util.Set;
 
 /**
- * CameraServiceProxy is the system_server analog to the camera service running in mediaserver.
+ * CameraServiceProxy is the system_server analog to the camera service running in cameraserver.
  *
  * @hide
  */
@@ -74,6 +74,7 @@
     private static final int MSG_SWITCH_USER = 1;
 
     private static final int RETRY_DELAY_TIME = 20; //ms
+    private static final int RETRY_TIMES = 30;
 
     // Maximum entries to keep in usage history before dumping out
     private static final int MAX_USAGE_HISTORY = 100;
@@ -171,7 +172,7 @@
                         " camera service UID!");
                 return;
             }
-            notifySwitchWithRetries(30);
+            notifySwitchWithRetries(RETRY_TIMES);
         }
 
         @Override
@@ -242,7 +243,8 @@
     public void onStartUser(int userHandle) {
         synchronized(mLock) {
             if (mEnabledCameraUsers == null) {
-                // Initialize mediaserver, or update mediaserver if we are recovering from a crash.
+                // Initialize cameraserver, or update cameraserver if we are recovering
+                // from a crash.
                 switchUserLocked(userHandle);
             }
         }
@@ -324,9 +326,9 @@
         Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
         mLastUser = userHandle;
         if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
-            // Some user handles have been added or removed, update mediaserver.
+            // Some user handles have been added or removed, update cameraserver.
             mEnabledCameraUsers = currentUserHandles;
-            notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, currentUserHandles);
+            notifySwitchWithRetriesLocked(RETRY_TIMES);
         }
     }
 
@@ -343,12 +345,16 @@
 
     private void notifySwitchWithRetries(int retries) {
         synchronized(mLock) {
-            if (mEnabledCameraUsers == null) {
-                return;
-            }
-            if (notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) {
-                retries = 0;
-            }
+            notifySwitchWithRetriesLocked(retries);
+        }
+    }
+
+    private void notifySwitchWithRetriesLocked(int retries) {
+        if (mEnabledCameraUsers == null) {
+            return;
+        }
+        if (notifyCameraserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) {
+            retries = 0;
         }
         if (retries <= 0) {
             return;
@@ -358,13 +364,13 @@
                 RETRY_DELAY_TIME);
     }
 
-    private boolean notifyMediaserverLocked(int eventType, Set<Integer> updatedUserHandles) {
-        // Forward the user switch event to the native camera service running in the mediaserver
+    private boolean notifyCameraserverLocked(int eventType, Set<Integer> updatedUserHandles) {
+        // Forward the user switch event to the native camera service running in the cameraserver
         // process.
         if (mCameraServiceRaw == null) {
             IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
             if (cameraServiceBinder == null) {
-                Slog.w(TAG, "Could not notify mediaserver, camera service not available.");
+                Slog.w(TAG, "Could not notify cameraserver, camera service not available.");
                 return false; // Camera service not active, cannot evict user clients.
             }
             try {
@@ -380,7 +386,7 @@
         try {
             mCameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles));
         } catch (RemoteException e) {
-            Slog.w(TAG, "Could not notify mediaserver, remote exception: " + e);
+            Slog.w(TAG, "Could not notify cameraserver, remote exception: " + e);
             // Not much we can do if camera service is dead.
             return false;
         }
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index da1360d..b6946023 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -469,7 +469,10 @@
      */
     @VisibleForTesting
     void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
-
+        if (mNetd == null) {
+            Log.e(TAG, "Failed to get the netd service");
+            return;
+        }
         ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
         ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
         ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 3010324..3abd0ba 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1269,21 +1269,14 @@
         return null;
     }
 
-    private boolean screenshotInternal(int displayId, Surface outSurface) {
+    private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId) {
         final IBinder token = getDisplayToken(displayId);
         if (token == null) {
-            return false;
+            return null;
         }
-        final SurfaceControl.ScreenshotGraphicBuffer gb =
-                SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
+        return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
                         token, new Rect(), 0 /* width */, 0 /* height */,
                         false /* useIdentityTransform */, 0 /* rotation */);
-        try {
-            outSurface.attachAndQueueBuffer(gb.getGraphicBuffer());
-        } catch (RuntimeException e) {
-            Slog.w(TAG, "Failed to take screenshot - " + e.getMessage());
-        }
-        return true;
     }
 
     @VisibleForTesting
@@ -2354,8 +2347,8 @@
         }
 
         @Override
-        public boolean screenshot(int displayId, Surface outSurface) {
-            return screenshotInternal(displayId, outSurface);
+        public SurfaceControl.ScreenshotGraphicBuffer screenshot(int displayId) {
+            return screenshotInternal(displayId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 9590f81..a7d0a5c 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -461,7 +461,9 @@
                     .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
         }
 
-        updateDisplayWhiteBalanceStatus();
+        if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
+            updateDisplayWhiteBalanceStatus();
+        }
 
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
         dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
@@ -624,7 +626,11 @@
             return false;
         }
         return Secure.getIntForUser(getContext().getContentResolver(),
-                Secure.DISPLAY_WHITE_BALANCE_ENABLED, 0, mCurrentUser) == 1;
+                Secure.DISPLAY_WHITE_BALANCE_ENABLED,
+                getContext().getResources()
+                        .getBoolean(R.bool.config_displayWhiteBalanceEnabledDefault) ? 1
+                        : 0,
+                mCurrentUser) == 1;
     }
 
     private boolean isDeviceColorManagedInternal() {
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 026837f..d6aa2ba 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -28,6 +28,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Arrays;
 
@@ -73,15 +74,27 @@
     private static final int SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR = 1023;
     private static final int SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED = 1030;
 
-    private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
-    private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
+    @VisibleForTesting
+    static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
+    @VisibleForTesting
+    static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
 
     private static final float COLOR_SATURATION_NATURAL = 1.0f;
     private static final float COLOR_SATURATION_BOOSTED = 1.1f;
 
+    /**
+     * Display color modes defined by DisplayColorSetting in
+     * frameworks/native/services/surfaceflinger/SurfaceFlinger.h.
+     */
     private static final int DISPLAY_COLOR_MANAGED = 0;
     private static final int DISPLAY_COLOR_UNMANAGED = 1;
     private static final int DISPLAY_COLOR_ENHANCED = 2;
+    /**
+     * Display color mode range reserved for vendor customizations by the RenderIntent definition in
+     * hardware/interfaces/graphics/common/1.1/types.hal.
+     */
+    private static final int VENDOR_MODE_RANGE_MIN = 256; // 0x100
+    private static final int VENDOR_MODE_RANGE_MAX = 511; // 0x1ff
 
     /**
      * Map of level -> color transformation matrix.
@@ -257,7 +270,11 @@
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
             applySaturation(COLOR_SATURATION_NATURAL);
             setDisplayColor(DISPLAY_COLOR_ENHANCED);
+        } else if (colorMode >= VENDOR_MODE_RANGE_MIN && colorMode <= VENDOR_MODE_RANGE_MAX) {
+            applySaturation(COLOR_SATURATION_NATURAL);
+            setDisplayColor(colorMode);
         }
+
         setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
 
         updateConfiguration();
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index e7181e2..c32ae97 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -271,7 +271,7 @@
         final long time = System.currentTimeMillis();
         float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time);
 
-        if (mAmbientToDisplayColorTemperatureSpline != null) {
+        if (mAmbientToDisplayColorTemperatureSpline != null && ambientColorTemperature != -1.0f) {
             ambientColorTemperature =
                 mAmbientToDisplayColorTemperatureSpline.interpolate(ambientColorTemperature);
         }
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index 647727f..0f73f37 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -36,6 +36,7 @@
 import android.os.Handler;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.Base64;
 import android.util.Slog;
@@ -69,9 +70,11 @@
     private final String mDriverPackageName;
     private final PackageManager mPackageManager;
     private final Object mLock = new Object();
+    private final Object mDeviceConfigLock = new Object();
     private ContentResolver mContentResolver;
     private long mGameDriverVersionCode;
     private SettingsObserver mSettingsObserver;
+    private DeviceConfigListener mDeviceConfigListener;
     @GuardedBy("mLock")
     private Blacklists mBlacklists;
 
@@ -101,10 +104,11 @@
     public void onBootPhase(int phase) {
         if (phase == PHASE_BOOT_COMPLETED) {
             mContentResolver = mContext.getContentResolver();
-            mSettingsObserver = new SettingsObserver();
             if (mDriverPackageName == null || mDriverPackageName.isEmpty()) {
                 return;
             }
+            mSettingsObserver = new SettingsObserver();
+            mDeviceConfigListener = new DeviceConfigListener();
             fetchGameDriverPackageProperties();
             processBlacklists();
             setBlacklist();
@@ -134,6 +138,24 @@
         }
     }
 
+    private final class DeviceConfigListener implements DeviceConfig.OnPropertyChangedListener {
+
+        DeviceConfigListener() {
+            super();
+            DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER,
+                    mContext.getMainExecutor(), this);
+        }
+        @Override
+        public void onPropertyChanged(String namespace, String name, String value) {
+            synchronized (mDeviceConfigLock) {
+                if (Settings.Global.GAME_DRIVER_BLACKLISTS.equals(name)) {
+                    parseBlacklists(value != null ? value : "");
+                    setBlacklist();
+                }
+            }
+        }
+    }
+
     private final class PackageReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
@@ -229,13 +251,17 @@
     }
 
     private void processBlacklists() {
-        // TODO(b/121350991) Switch to DeviceConfig with property listener.
-        String base64String =
-                Settings.Global.getString(mContentResolver, Settings.Global.GAME_DRIVER_BLACKLISTS);
-        if (base64String == null || base64String.isEmpty()) {
-            return;
+        String base64String = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_GAME_DRIVER,
+                Settings.Global.GAME_DRIVER_BLACKLISTS);
+        if (base64String == null) {
+            base64String =
+                    Settings.Global.getString(mContentResolver,
+                                              Settings.Global.GAME_DRIVER_BLACKLISTS);
         }
+        parseBlacklists(base64String != null ? base64String : "");
+    }
 
+    private void parseBlacklists(String base64String) {
         synchronized (mLock) {
             // Reset all blacklists
             mBlacklists = null;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 647e952..e88d62f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -231,6 +231,7 @@
             Context.BIND_AUTO_CREATE
             | Context.BIND_TREAT_LIKE_ACTIVITY
             | Context.BIND_FOREGROUND_SERVICE
+            | Context.BIND_INCLUDE_CAPABILITIES
             | Context.BIND_SHOWING_UI
             | Context.BIND_SCHEDULE_LIKE_TOP_APP;
 
@@ -4100,13 +4101,15 @@
 
     // ----------------------------------------------------------------------
 
-    boolean setInputMethodEnabledLocked(String id, boolean enabled) {
-        // Make sure this is a valid input method.
-        InputMethodInfo imm = mMethodMap.get(id);
-        if (imm == null) {
-            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
-        }
-
+    /**
+     * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+     *
+     * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
+     *           recognized by the system.
+     * @param enabled {@code true} if {@code id} needs to be enabled.
+     * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
+     */
+    private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
         List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
                 .getEnabledInputMethodsAndSubtypeListLocked();
 
@@ -4586,25 +4589,42 @@
                 pw.decreaseIndent();
                 pw.decreaseIndent();
 
-                pw.println("enable <ID>");
+                pw.println("enable [--user <USER_ID>] <ID>");
                 pw.increaseIndent();
                 pw.println("allows the given input method ID to be used.");
+                pw.increaseIndent();
+                pw.print("--user <USER_ID>: Specify which user to enable.");
+                pw.println(" Assumes the current user if not specified.");
+                pw.decreaseIndent();
                 pw.decreaseIndent();
 
-                pw.println("disable <ID>");
+                pw.println("disable [--user <USER_ID>] <ID>");
                 pw.increaseIndent();
                 pw.println("disallows the given input method ID to be used.");
+                pw.increaseIndent();
+                pw.print("--user <USER_ID>: Specify which user to disable.");
+                pw.println(" Assumes the current user if not specified.");
+                pw.decreaseIndent();
                 pw.decreaseIndent();
 
-                pw.println("set <ID>");
+                pw.println("set [--user <USER_ID>] <ID>");
                 pw.increaseIndent();
                 pw.println("switches to the given input method ID.");
+                pw.increaseIndent();
+                pw.print("--user <USER_ID>: Specify which user to enable.");
+                pw.println(" Assumes the current user if not specified.");
+                pw.decreaseIndent();
                 pw.decreaseIndent();
 
-                pw.println("reset");
+                pw.println("reset [--user <USER_ID>]");
                 pw.increaseIndent();
                 pw.println("reset currently selected/enabled IMEs to the default ones as if "
                         + "the device is initially booted with the current locale.");
+                pw.increaseIndent();
+                pw.print("--user <USER_ID>: Specify which user to reset.");
+                pw.println(" Assumes the current user if not specified.");
+                pw.decreaseIndent();
+
                 pw.decreaseIndent();
 
                 pw.decreaseIndent();
@@ -4690,24 +4710,108 @@
     @ShellCommandResult
     private int handleShellCommandEnableDisableInputMethod(
             @NonNull ShellCommand shellCommand, boolean enabled) {
-        final String id = shellCommand.getNextArgRequired();
-        final boolean previouslyEnabled;
+        final String imeId = shellCommand.getNextArgRequired();
+        final PrintWriter out = shellCommand.getOutPrintWriter();
+        final PrintWriter error = shellCommand.getErrPrintWriter();
+        final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
         synchronized (mMethodMap) {
-            if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
-                return ShellCommandResult.SUCCESS;
+            final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+                    mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+            for (int userId : userIds) {
+                if (!userHasDebugPriv(userId, shellCommand)) {
+                    continue;
+                }
+                handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
+                        out, error);
             }
-            previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
         }
-        final PrintWriter pr = shellCommand.getOutPrintWriter();
-        pr.print("Input method ");
-        pr.print(id);
-        pr.print(": ");
-        pr.print((enabled == previouslyEnabled) ? "already " : "now ");
-        pr.println(enabled ? "enabled" : "disabled");
         return ShellCommandResult.SUCCESS;
     }
 
     /**
+     * A special helper method for commands that only have {@code -u} and {@code --user} options.
+     *
+     * <p>You cannot use this helper method if the command has other options.</p>
+     *
+     * @param shellCommand {@link ShellCommand} from which options should be obtained.
+     * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
+     */
+    @BinderThread
+    @UserIdInt
+    private static int handleOptionsForCommandsThatOnlyHaveUserOption(ShellCommand shellCommand) {
+        while (true) {
+            final String nextOption = shellCommand.getNextOption();
+            if (nextOption == null) {
+                break;
+            }
+            switch (nextOption) {
+                case "-u":
+                case "--user":
+                    return UserHandle.parseUserArg(shellCommand.getNextArgRequired());
+            }
+        }
+        return UserHandle.USER_CURRENT;
+    }
+
+    @BinderThread
+    private void handleShellCommandEnableDisableInputMethodInternalLocked(
+            @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
+            PrintWriter error) {
+        boolean failedToEnableUnknownIme = false;
+        boolean previouslyEnabled = false;
+        if (userId == mSettings.getCurrentUserId()) {
+            if (enabled && !mMethodMap.containsKey(imeId)) {
+                failedToEnableUnknownIme = true;
+            } else {
+                previouslyEnabled = setInputMethodEnabledLocked(imeId, enabled);
+            }
+        } else {
+            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, userId, false);
+            if (enabled) {
+                if (!methodMap.containsKey(imeId)) {
+                    failedToEnableUnknownIme = true;
+                } else {
+                    for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) {
+                        if (TextUtils.equals(imi.getId(), imeId)) {
+                            previouslyEnabled = true;
+                            break;
+                        }
+                    }
+                    if (!previouslyEnabled) {
+                        settings.appendAndPutEnabledInputMethodLocked(imeId, false);
+                    }
+                }
+            } else {
+                previouslyEnabled =
+                        settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
+                                new StringBuilder(),
+                                settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
+            }
+        }
+        if (failedToEnableUnknownIme) {
+            error.print("Unknown input method ");
+            error.print(imeId);
+            error.println(" cannot be enabled for user #" + userId);
+        } else {
+            out.print("Input method ");
+            out.print(imeId);
+            out.print(": ");
+            out.print((enabled == previouslyEnabled) ? "already " : "now ");
+            out.print(enabled ? "enabled" : "disabled");
+            out.print(" for user #");
+            out.println(userId);
+        }
+    }
+
+    /**
      * Handles {@code adb shell ime set}.
      * @param shellCommand {@link ShellCommand} object that is handling this command.
      * @return Exit code of the command.
@@ -4715,17 +4819,55 @@
     @BinderThread
     @ShellCommandResult
     private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
-        final String id = shellCommand.getNextArgRequired();
+        final String imeId = shellCommand.getNextArgRequired();
+        final PrintWriter out = shellCommand.getOutPrintWriter();
+        final PrintWriter error = shellCommand.getErrPrintWriter();
+        final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
         synchronized (mMethodMap) {
-            if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
-                return ShellCommandResult.SUCCESS;
+            final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+                    mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+            for (int userId : userIds) {
+                if (!userHasDebugPriv(userId, shellCommand)) {
+                    continue;
+                }
+                boolean failedToSelectUnknownIme = false;
+                if (userId == mSettings.getCurrentUserId()) {
+                    if (mMethodMap.containsKey(imeId)) {
+                        setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
+                    } else {
+                        failedToSelectUnknownIme = true;
+                    }
+                } else {
+                    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,
+                            userId, false);
+                    if (methodMap.containsKey(imeId)) {
+                        settings.putSelectedInputMethod(imeId);
+                        settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
+                    } else {
+                        failedToSelectUnknownIme = true;
+                    }
+                }
+                if (failedToSelectUnknownIme) {
+                    error.print("Unknown input method ");
+                    error.print(imeId);
+                    error.print(" cannot be selected for user #");
+                    error.println(userId);
+                } else {
+                    out.print("Input method ");
+                    out.print(imeId);
+                    out.print(" selected for user #");
+                    error.println(userId);
+                }
             }
-            setInputMethodLocked(id, NOT_A_SUBTYPE_ID);
         }
-        final PrintWriter pr = shellCommand.getOutPrintWriter();
-        pr.print("Input method ");
-        pr.print(id);
-        pr.println("  selected");
         return ShellCommandResult.SUCCESS;
     }
 
@@ -4737,45 +4879,67 @@
     @BinderThread
     @ShellCommandResult
     private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
+        final PrintWriter out = shellCommand.getOutPrintWriter();
+        final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
         synchronized (mMethodMap) {
-            if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
-                return ShellCommandResult.SUCCESS;
-            }
-            final String nextIme;
-            final List<InputMethodInfo> nextEnabledImes;
-            hideCurrentInputLocked(0, null);
-            unbindCurrentMethodLocked();
-            // Reset the current IME
-            resetSelectedInputMethodAndSubtypeLocked(null);
-            // Also reset the settings of the current IME
-            mSettings.putSelectedInputMethod(null);
-            // Disable all enabled IMEs.
-            mSettings.getEnabledInputMethodListLocked().forEach(
-                    imi -> setInputMethodEnabledLocked(imi.getId(), false));
-            // Re-enable with default enabled IMEs.
-            InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
-                    imi -> setInputMethodEnabledLocked(imi.getId(), true));
-            updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
-            InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
-                    mSettings.getEnabledInputMethodListLocked(),
-                    mSettings.getCurrentUserId(),
-                    mContext.getBasePackageName());
-            nextIme = mSettings.getSelectedInputMethod();
-            nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
-            final PrintWriter pr = shellCommand.getOutPrintWriter();
-            pr.println("Reset current and enabled IMEs");
-            pr.println("Newly selected IME:");
-            pr.print("  "); pr.println(nextIme);
-            pr.println("Newly enabled IMEs:");
-            {
-                final int N = nextEnabledImes.size();
-                for (int i = 0; i < N; ++i) {
-                    pr.print("  ");
-                    pr.println(nextEnabledImes.get(i).getId());
+            final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+                    mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+            for (int userId : userIds) {
+                if (!userHasDebugPriv(userId, shellCommand)) {
+                    continue;
                 }
+                final String nextIme;
+                final List<InputMethodInfo> nextEnabledImes;
+                if (userId == mSettings.getCurrentUserId()) {
+                    hideCurrentInputLocked(0, null);
+                    unbindCurrentMethodLocked();
+                    // Reset the current IME
+                    resetSelectedInputMethodAndSubtypeLocked(null);
+                    // Also reset the settings of the current IME
+                    mSettings.putSelectedInputMethod(null);
+                    // Disable all enabled IMEs.
+                    mSettings.getEnabledInputMethodListLocked().forEach(
+                            imi -> setInputMethodEnabledLocked(imi.getId(), false));
+                    // Re-enable with default enabled IMEs.
+                    InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
+                            imi -> setInputMethodEnabledLocked(imi.getId(), true));
+                    updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
+                    InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
+                            mSettings.getEnabledInputMethodListLocked(),
+                            mSettings.getCurrentUserId(),
+                            mContext.getBasePackageName());
+                    nextIme = mSettings.getSelectedInputMethod();
+                    nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
+                } else {
+                    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,
+                            userId, false);
+
+                    nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
+                    nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
+
+                    // Reset enabled IMEs.
+                    settings.putEnabledInputMethodsStr("");
+                    nextEnabledImes.forEach(imi -> settings.appendAndPutEnabledInputMethodLocked(
+                            imi.getId(), false));
+
+                    // Reset selected IME.
+                    settings.putSelectedInputMethod(nextIme);
+                    settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
+                }
+                out.println("Reset current and enabled IMEs for user #" + userId);
+                out.println("  Selected: " + nextIme);
+                nextEnabledImes.forEach(ime -> out.println("   Enabled: " + ime.getId()));
             }
-            return ShellCommandResult.SUCCESS;
         }
+        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 4349b4a..b5e19ae 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -1003,7 +1003,7 @@
             return res;
         }
 
-        private void putEnabledInputMethodsStr(@Nullable String str) {
+        void putEnabledInputMethodsStr(@Nullable String str) {
             if (DEBUG) {
                 Slog.d(TAG, "putEnabledInputMethodStr: " + str);
             }
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index ab75b21..2e72fbd 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -199,29 +199,27 @@
     }
 
     /**
-     * called from native code to update AGPS status
+     * Called from native code to update AGPS connection status, or to request or release a SUPL
+     * connection.
+     *
+     * <p>Note: {@code suplIpAddr} parameter is not present from IAGnssCallback.hal@2.0 onwards
+     * and is set to {@code null}.
      */
     void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
+        if (DEBUG) Log.d(TAG, "AGPS_DATA_CONNECTION: " + agpsDataConnStatusAsString(agpsStatus));
         switch (agpsStatus) {
             case GPS_REQUEST_AGPS_DATA_CONN:
-                if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
                 runOnHandler(() -> handleRequestSuplConnection(agpsType, suplIpAddr));
                 break;
             case GPS_RELEASE_AGPS_DATA_CONN:
-                if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
                 runOnHandler(() -> handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN));
                 break;
             case GPS_AGPS_DATA_CONNECTED:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
-                break;
             case GPS_AGPS_DATA_CONN_DONE:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
-                break;
             case GPS_AGPS_DATA_CONN_FAILED:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
                 break;
             default:
-                if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + agpsStatus);
+                Log.w(TAG, "Received unknown AGPS status: " + agpsStatus);
         }
     }
 
@@ -459,11 +457,15 @@
         }
         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
 
-        NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
-        requestBuilder.addCapability(getNetworkCapability(mAGpsType));
-        NetworkRequest request = requestBuilder.build();
+        // The transport type must be set to NetworkCapabilities.TRANSPORT_CELLULAR for the
+        // deprecated requestRouteToHostAddress() method in ConnectivityService to work for
+        // pre-gnss@2.0 devices.
+        NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+        networkRequestBuilder.addCapability(getNetworkCapability(mAGpsType));
+        networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        NetworkRequest networkRequest = networkRequestBuilder.build();
         mConnMgr.requestNetwork(
-                request,
+                networkRequest,
                 mSuplConnectivityCallback,
                 mHandler,
                 SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
@@ -546,7 +548,7 @@
             case AGPS_DATA_CONNECTION_OPENING:
                 return "OPENING";
             default:
-                return "<Unknown>";
+                return "<Unknown>(" + mAGpsDataConnectionState + ")";
         }
     }
 
@@ -566,7 +568,7 @@
             case GPS_REQUEST_AGPS_DATA_CONN:
                 return "REQUEST";
             default:
-                return "<Unknown>";
+                return "<Unknown>(" + agpsDataConnStatus + ")";
         }
     }
 
@@ -581,7 +583,7 @@
             case AGPS_TYPE_IMS:
                 return "IMS";
             default:
-                return "<Unknown>";
+                return "<Unknown>(" + agpsType + ")";
         }
     }
 
@@ -658,4 +660,4 @@
 
     private native void native_update_network_state(boolean connected, int type, boolean roaming,
             boolean available, String apn, long networkHandle, short capabilities);
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 0cabf1d..de36dea 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -1489,8 +1489,10 @@
             final long token = Binder.clearCallingIdentity();
 
             if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
-                        + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
+                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName
+                        + ", opPkg=" + opPackageName + ", pid=" + pid + ", uid=" + uid
+                        + ", asSystem=" + asSystemService + ", event=" + keyEvent
+                        + ", stream=" + stream + ", musicOnly=" + musicOnly);
             }
 
             try {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 1559911..f34ace5 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -25,6 +25,7 @@
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkStack.checkNetworkStackPermission;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.INTERFACES_ALL;
@@ -866,7 +867,7 @@
             VpnInfo[] vpnArray,
             NetworkState[] networkStates,
             String activeIface) {
-        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+        checkNetworkStackPermission(mContext);
         assertBandwidthControlEnabled();
 
         final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0488d3a..4a6eb27 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -79,7 +79,6 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.function.Predicate;
 
 /**
  * Manages the lifecycle of application-provided services bound by system server.
@@ -1163,6 +1162,7 @@
                 @Override
                 public void onNullBinding(ComponentName name) {
                     Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
+                    mServicesBound.remove(servicesBindingTag);
                 }
             };
             if (!mContext.bindServiceAsUser(intent,
@@ -1180,6 +1180,11 @@
         }
     }
 
+    boolean isBound(ComponentName cn, int userId) {
+        final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(cn, userId);
+        return mServicesBound.contains(servicesBindingTag);
+    }
+
     /**
      * Remove a service for the given user by ComponentName
      */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f2e56b5..7f1b25ca 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -29,6 +29,7 @@
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
@@ -1515,6 +1516,11 @@
     }
 
     @VisibleForTesting
+    void setZenHelper(ZenModeHelper zenHelper) {
+        mZenModeHelper = zenHelper;
+    }
+
+    @VisibleForTesting
     void setIsAutomotive(boolean isAutomotive) {
         mIsAutomotive = isAutomotive;
     }
@@ -2855,7 +2861,7 @@
         }
 
         @Override
-        public List<String> getAllowedAssistantCapabilities(String pkg) {
+        public List<String> getAllowedAssistantAdjustments(String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
 
             if (!isCallerSystemOrPhone()
@@ -2863,20 +2869,20 @@
                     throw new SecurityException("Not currently an assistant");
             }
 
-            return mAssistants.getAllowedAssistantCapabilities();
+            return mAssistants.getAllowedAssistantAdjustments();
         }
 
         @Override
-        public void allowAssistantCapability(String adjustmentType) {
-            checkCallerIsSystemOrShell();
+        public void allowAssistantAdjustment(String adjustmentType) {
+            checkCallerIsSystemOrSystemUiOrShell();
             mAssistants.allowAdjustmentType(adjustmentType);
 
             handleSavePolicyFile();
         }
 
         @Override
-        public void disallowAssistantCapability(String adjustmentType) {
-            checkCallerIsSystemOrShell();
+        public void disallowAssistantAdjustment(String adjustmentType) {
+            checkCallerIsSystemOrSystemUiOrShell();
             mAssistants.disallowAdjustmentType(adjustmentType);
 
             handleSavePolicyFile();
@@ -3419,8 +3425,7 @@
         }
 
         @Override
-        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
-                throws RemoteException {
+        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
             if (automaticZenRule.getOwner() == null
@@ -3429,6 +3434,11 @@
                         "Rule must have a conditionproviderservice and/or configuration activity");
             }
             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
+            if (automaticZenRule.getZenPolicy() != null
+                    && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
+                throw new IllegalArgumentException("ZenPolicy is only applicable to "
+                        + "INTERRUPTION_FILTER_PRIORITY filters");
+            }
             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
 
             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
@@ -3558,7 +3568,7 @@
                 return;
             }
             boolean accessAllowed = false;
-            String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+            String[] packages = mPackageManagerClient.getPackagesForUid(uid);
             final int packageCount = packages.length;
             for (int i = 0; i < packageCount; i++) {
                 if (mConditionProviders.isPackageOrComponentAllowed(
@@ -3806,7 +3816,7 @@
 
         @Override
         public ComponentName getAllowedNotificationAssistantForUser(int userId) {
-            checkCallerIsSystem();
+            checkCallerIsSystemOrSystemUiOrShell();
             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
             if (allowedComponents.size() > 1) {
                 throw new IllegalStateException(
@@ -3889,7 +3899,7 @@
         @Override
         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
                 int userId, boolean granted) {
-            checkCallerIsSystemOrShell();
+            checkCallerIsSystemOrSystemUiOrShell();
             mAssistants.setUserSet(userId, true);
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -3924,10 +3934,6 @@
                         }
                     }
                     if (!foundEnqueued) {
-                        // adjustment arrived too late to apply to enqueued; apply to posted
-                        // However, since the notification is now posted and may have alerted,
-                        // ignore any importance related adjustments
-                        adjustment.getSignals().remove(Adjustment.KEY_IMPORTANCE);
                         applyAdjustmentFromAssistant(token, adjustment);
                     }
                 }
@@ -4118,7 +4124,7 @@
             }
             return;
         }
-        if (mAllowedManagedServicePackages.test(assistant.getPackageName(), userId,
+        if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), userId,
                 mAssistants.getRequiredPermission())) {
             mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
                     userId, false, granted);
@@ -6990,6 +6996,16 @@
         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
     }
 
+    private void checkCallerIsSystemOrSystemUiOrShell() {
+        if (Binder.getCallingUid() == Process.SHELL_UID) {
+            return;
+        }
+        if (isCallerSystemOrPhone()) {
+            return;
+        }
+        getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null);
+    }
+
     private void checkCallerIsSystemOrSameApp(String pkg) {
         if (isCallerSystemOrPhone()) {
             return;
@@ -7297,7 +7313,7 @@
 
         @GuardedBy("mLock")
         private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
-        private List<String> mAllowedAdjustments = new ArrayList<>();
+        private Set<String> mAllowedAdjustments = new ArraySet<>();
 
         public NotificationAssistants(Context context, Object lock, UserProfiles up,
                 IPackageManager pm) {
@@ -7385,15 +7401,21 @@
             synchronized (mLock) {
                 mAllowedAdjustments.add(type);
             }
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                mHandler.post(() -> notifyCapabilitiesChanged(info));
+            }
         }
 
         protected void disallowAdjustmentType(String type) {
             synchronized (mLock) {
                 mAllowedAdjustments.remove(type);
             }
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                    mHandler.post(() -> notifyCapabilitiesChanged(info));
+            }
         }
 
-        protected List<String> getAllowedAssistantCapabilities() {
+        protected List<String> getAllowedAssistantAdjustments() {
             synchronized (mLock) {
                 List<String> types = new ArrayList<>();
                 types.addAll(mAllowedAdjustments);
@@ -7450,6 +7472,15 @@
             setUserSet(userId, userSet);
         }
 
+        private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
+            final INotificationListener assistant = (INotificationListener) info.service;
+            try {
+                assistant.onAllowedAdjustmentsChanged();
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
+            }
+        }
+
         private void notifySeen(final ManagedServiceInfo info,
                 final ArrayList<String> keys) {
             final INotificationListener assistant = (INotificationListener) info.service;
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index f34b2cb..642fa7f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -38,7 +38,6 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
@@ -180,7 +179,7 @@
                                 }
                             }
 
-                            PackagePreferences r = getOrCreatePackagePreferences(name, uid,
+                            PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid,
                                     XmlUtils.readIntAttribute(
                                             parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
                                     XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
@@ -264,9 +263,9 @@
                             }
 
                             try {
-                                deleteDefaultChannelIfNeeded(r);
+                                deleteDefaultChannelIfNeededLocked(r);
                             } catch (PackageManager.NameNotFoundException e) {
-                                Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e);
+                                Slog.e(TAG, "deleteDefaultChannelIfNeededLocked - Exception: " + e);
                             }
                         }
                     }
@@ -276,50 +275,46 @@
         throw new IllegalStateException("Failed to reach END_DOCUMENT");
     }
 
-    private PackagePreferences getPackagePreferences(String pkg, int uid) {
+    private PackagePreferences getPackagePreferencesLocked(String pkg, int uid) {
         final String key = packagePreferencesKey(pkg, uid);
-        synchronized (mPackagePreferences) {
-            return mPackagePreferences.get(key);
-        }
+        return mPackagePreferences.get(key);
     }
 
-    private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid,
+    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) {
+        return getOrCreatePackagePreferencesLocked(pkg, uid,
                 DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
                 DEFAULT_ALLOW_BUBBLE);
     }
 
-    private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance,
-            int priority, int visibility, boolean showBadge, boolean allowBubble) {
+    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid,
+            int importance, int priority, int visibility, boolean showBadge, boolean allowBubble) {
         final String key = packagePreferencesKey(pkg, uid);
-        synchronized (mPackagePreferences) {
-            PackagePreferences
-                    r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
-                    : mPackagePreferences.get(key);
-            if (r == null) {
-                r = new PackagePreferences();
-                r.pkg = pkg;
-                r.uid = uid;
-                r.importance = importance;
-                r.priority = priority;
-                r.visibility = visibility;
-                r.showBadge = showBadge;
-                r.allowBubble = allowBubble;
+        PackagePreferences
+                r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
+                : mPackagePreferences.get(key);
+        if (r == null) {
+            r = new PackagePreferences();
+            r.pkg = pkg;
+            r.uid = uid;
+            r.importance = importance;
+            r.priority = priority;
+            r.visibility = visibility;
+            r.showBadge = showBadge;
+            r.allowBubble = allowBubble;
 
-                try {
-                    createDefaultChannelIfNeeded(r);
-                } catch (PackageManager.NameNotFoundException e) {
-                    Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e);
-                }
-
-                if (r.uid == UNKNOWN_UID) {
-                    mRestoredWithoutUids.put(pkg, r);
-                } else {
-                    mPackagePreferences.put(key, r);
-                }
+            try {
+                createDefaultChannelIfNeededLocked(r);
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.e(TAG, "createDefaultChannelIfNeededLocked - Exception: " + e);
             }
-            return r;
+
+            if (r.uid == UNKNOWN_UID) {
+                mRestoredWithoutUids.put(pkg, r);
+            } else {
+                mPackagePreferences.put(key, r);
+            }
         }
+        return r;
     }
 
     private boolean shouldHaveDefaultChannel(PackagePreferences r) throws
@@ -336,7 +331,7 @@
         return true;
     }
 
-    private void deleteDefaultChannelIfNeeded(PackagePreferences r) throws
+    private void deleteDefaultChannelIfNeededLocked(PackagePreferences r) throws
             PackageManager.NameNotFoundException {
         if (!r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
             // Not present
@@ -352,7 +347,7 @@
         r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
     }
 
-    private void createDefaultChannelIfNeeded(PackagePreferences r) throws
+    private void createDefaultChannelIfNeededLocked(PackagePreferences r) throws
             PackageManager.NameNotFoundException {
         if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
             r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(mContext.getString(
@@ -479,9 +474,11 @@
      * @param allowed whether bubbles are allowed.
      */
     public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
-        PackagePreferences p = getOrCreatePackagePreferences(pkg, uid);
-        p.allowBubble = allowed;
-        p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE;
+        synchronized (mPackagePreferences) {
+            PackagePreferences p = getOrCreatePackagePreferencesLocked(pkg, uid);
+            p.allowBubble = allowed;
+            p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE;
+        }
     }
 
     /**
@@ -493,11 +490,15 @@
      */
     @Override
     public boolean areBubblesAllowed(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).allowBubble;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).allowBubble;
+        }
     }
 
     public int getAppLockedFields(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).lockedAppFields;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).lockedAppFields;
+        }
     }
 
     /**
@@ -505,7 +506,9 @@
      */
     @Override
     public int getImportance(String packageName, int uid) {
-        return getOrCreatePackagePreferences(packageName, uid).importance;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(packageName, uid).importance;
+        }
     }
 
     /**
@@ -514,18 +517,24 @@
      * locking field, see {@link NotificationChannel#USER_LOCKED_IMPORTANCE}.
      */
     public boolean getIsAppImportanceLocked(String packageName, int uid) {
-        int userLockedFields = getOrCreatePackagePreferences(packageName, uid).lockedAppFields;
-        return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0;
+        synchronized (mPackagePreferences) {
+            int userLockedFields = getOrCreatePackagePreferencesLocked(packageName, uid).lockedAppFields;
+            return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0;
+        }
     }
 
     @Override
     public boolean canShowBadge(String packageName, int uid) {
-        return getOrCreatePackagePreferences(packageName, uid).showBadge;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(packageName, uid).showBadge;
+        }
     }
 
     @Override
     public void setShowBadge(String packageName, int uid, boolean showBadge) {
-        getOrCreatePackagePreferences(packageName, uid).showBadge = showBadge;
+        synchronized (mPackagePreferences) {
+            getOrCreatePackagePreferencesLocked(packageName, uid).showBadge = showBadge;
+        }
         updateConfig();
     }
 
@@ -534,20 +543,26 @@
         if (groupId == null) {
             return false;
         }
-        PackagePreferences r = getOrCreatePackagePreferences(packageName, uid);
-        NotificationChannelGroup group = r.groups.get(groupId);
-        if (group == null) {
-            return false;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+            NotificationChannelGroup group = r.groups.get(groupId);
+            if (group == null) {
+                return false;
+            }
+            return group.isBlocked();
         }
-        return group.isBlocked();
     }
 
     int getPackagePriority(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).priority;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).priority;
+        }
     }
 
     int getPackageVisibility(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).visibility;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).visibility;
+        }
     }
 
     @Override
@@ -557,32 +572,34 @@
         Preconditions.checkNotNull(group);
         Preconditions.checkNotNull(group.getId());
         Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName()));
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
-        }
-        final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
-        if (!group.equals(oldGroup)) {
-            // will log for new entries as well as name/description changes
-            MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
-        }
-        if (oldGroup != null) {
-            group.setChannels(oldGroup.getChannels());
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                throw new IllegalArgumentException("Invalid package");
+            }
+            final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
+            if (!group.equals(oldGroup)) {
+                // will log for new entries as well as name/description changes
+                MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
+            }
+            if (oldGroup != null) {
+                group.setChannels(oldGroup.getChannels());
 
-            // apps can't update the blocked status or app overlay permission
-            if (fromTargetApp) {
-                group.setBlocked(oldGroup.isBlocked());
-                group.unlockFields(group.getUserLockedFields());
-                group.lockFields(oldGroup.getUserLockedFields());
-            } else {
-                // but the system can
-                if (group.isBlocked() != oldGroup.isBlocked()) {
-                    group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
-                    updateChannelsBypassingDnd(mContext.getUserId());
+                // apps can't update the blocked status or app overlay permission
+                if (fromTargetApp) {
+                    group.setBlocked(oldGroup.isBlocked());
+                    group.unlockFields(group.getUserLockedFields());
+                    group.lockFields(oldGroup.getUserLockedFields());
+                } else {
+                    // but the system can
+                    if (group.isBlocked() != oldGroup.isBlocked()) {
+                        group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
+                        updateChannelsBypassingDnd(mContext.getUserId());
+                    }
                 }
             }
+            r.groups.put(group.getId(), group);
         }
-        r.groups.put(group.getId(), group);
     }
 
     @Override
@@ -592,94 +609,96 @@
         Preconditions.checkNotNull(channel);
         Preconditions.checkNotNull(channel.getId());
         Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName()));
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
-        }
-        if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) {
-            throw new IllegalArgumentException("NotificationChannelGroup doesn't exist");
-        }
-        if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
-            throw new IllegalArgumentException("Reserved id");
-        }
-        NotificationChannel existing = r.channels.get(channel.getId());
-        // Keep most of the existing settings
-        if (existing != null && fromTargetApp) {
-            if (existing.isDeleted()) {
-                existing.setDeleted(false);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                throw new IllegalArgumentException("Invalid package");
+            }
+            if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) {
+                throw new IllegalArgumentException("NotificationChannelGroup doesn't exist");
+            }
+            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
+                throw new IllegalArgumentException("Reserved id");
+            }
+            NotificationChannel existing = r.channels.get(channel.getId());
+            // Keep most of the existing settings
+            if (existing != null && fromTargetApp) {
+                if (existing.isDeleted()) {
+                    existing.setDeleted(false);
 
-                // log a resurrected channel as if it's new again
-                MetricsLogger.action(getChannelLog(channel, pkg).setType(
-                        com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
+                    // log a resurrected channel as if it's new again
+                    MetricsLogger.action(getChannelLog(channel, pkg).setType(
+                            com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
+                }
+
+                existing.setName(channel.getName().toString());
+                existing.setDescription(channel.getDescription());
+                existing.setBlockableSystem(channel.isBlockableSystem());
+                if (existing.getGroup() == null) {
+                    existing.setGroup(channel.getGroup());
+                }
+
+                // Apps are allowed to downgrade channel importance if the user has not changed any
+                // fields on this channel yet.
+                final int previousExistingImportance = existing.getImportance();
+                if (existing.getUserLockedFields() == 0 &&
+                        channel.getImportance() < existing.getImportance()) {
+                    existing.setImportance(channel.getImportance());
+                }
+
+                // system apps and dnd access apps can bypass dnd if the user hasn't changed any
+                // fields on the channel yet
+                if (existing.getUserLockedFields() == 0 && hasDndAccess) {
+                    boolean bypassDnd = channel.canBypassDnd();
+                    existing.setBypassDnd(bypassDnd);
+
+                    if (bypassDnd != mAreChannelsBypassingDnd
+                            || previousExistingImportance != existing.getImportance()) {
+                        updateChannelsBypassingDnd(mContext.getUserId());
+                    }
+                }
+
+                updateConfig();
+                return;
+            }
+            if (channel.getImportance() < IMPORTANCE_NONE
+                    || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) {
+                throw new IllegalArgumentException("Invalid importance level");
             }
 
-            existing.setName(channel.getName().toString());
-            existing.setDescription(channel.getDescription());
-            existing.setBlockableSystem(channel.isBlockableSystem());
-            if (existing.getGroup() == null) {
-                existing.setGroup(channel.getGroup());
+            // Reset fields that apps aren't allowed to set.
+            if (fromTargetApp && !hasDndAccess) {
+                channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
             }
-
-            // Apps are allowed to downgrade channel importance if the user has not changed any
-            // fields on this channel yet.
-            final int previousExistingImportance = existing.getImportance();
-            if (existing.getUserLockedFields() == 0 &&
-                    channel.getImportance() < existing.getImportance()) {
-                existing.setImportance(channel.getImportance());
+            if (fromTargetApp) {
+                channel.setLockscreenVisibility(r.visibility);
             }
-
-            // system apps and dnd access apps can bypass dnd if the user hasn't changed any
-            // fields on the channel yet
-            if (existing.getUserLockedFields() == 0 && hasDndAccess) {
-                boolean bypassDnd = channel.canBypassDnd();
-                existing.setBypassDnd(bypassDnd);
-
-                if (bypassDnd != mAreChannelsBypassingDnd
-                        || previousExistingImportance != existing.getImportance()) {
-                    updateChannelsBypassingDnd(mContext.getUserId());
+            clearLockedFieldsLocked(channel);
+            channel.setImportanceLockedByOEM(r.oemLockedImportance);
+            if (!channel.isImportanceLockedByOEM()) {
+                if (r.futureOemLockedChannels.remove(channel.getId())) {
+                    channel.setImportanceLockedByOEM(true);
                 }
             }
-
-            updateConfig();
-            return;
-        }
-        if (channel.getImportance() < IMPORTANCE_NONE
-                || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) {
-            throw new IllegalArgumentException("Invalid importance level");
-        }
-
-        // Reset fields that apps aren't allowed to set.
-        if (fromTargetApp && !hasDndAccess) {
-            channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
-        }
-        if (fromTargetApp) {
-            channel.setLockscreenVisibility(r.visibility);
-        }
-        clearLockedFields(channel);
-        channel.setImportanceLockedByOEM(r.oemLockedImportance);
-        if (!channel.isImportanceLockedByOEM()) {
-            if (r.futureOemLockedChannels.remove(channel.getId())) {
-                channel.setImportanceLockedByOEM(true);
+            channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
+            if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
+                channel.setLockscreenVisibility(
+                        NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
             }
-        }
-        channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
-        if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
-            channel.setLockscreenVisibility(
-                    NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
-        }
-        if (!r.showBadge) {
-            channel.setShowBadge(false);
-        }
+            if (!r.showBadge) {
+                channel.setShowBadge(false);
+            }
 
-        r.channels.put(channel.getId(), channel);
-        if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
-            updateChannelsBypassingDnd(mContext.getUserId());
+            r.channels.put(channel.getId(), channel);
+            if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
+                updateChannelsBypassingDnd(mContext.getUserId());
+            }
+            MetricsLogger.action(getChannelLog(channel, pkg).setType(
+                    com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
         }
-        MetricsLogger.action(getChannelLog(channel, pkg).setType(
-                com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
     }
 
-    void clearLockedFields(NotificationChannel channel) {
+    void clearLockedFieldsLocked(NotificationChannel channel) {
         channel.unlockFields(channel.getUserLockedFields());
     }
 
@@ -688,55 +707,58 @@
             boolean fromUser) {
         Preconditions.checkNotNull(updatedChannel);
         Preconditions.checkNotNull(updatedChannel.getId());
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
-        }
-        NotificationChannel channel = r.channels.get(updatedChannel.getId());
-        if (channel == null || channel.isDeleted()) {
-            throw new IllegalArgumentException("Channel does not exist");
-        }
-        if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
-            updatedChannel.setLockscreenVisibility(
-                    NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
-        }
-        if (fromUser) {
-            updatedChannel.lockFields(channel.getUserLockedFields());
-            lockFieldsForUpdate(channel, updatedChannel);
-        } 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());
-        }
-        updatedChannel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
-        if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) {
-            updatedChannel.setImportance(channel.getImportance());
-        }
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                throw new IllegalArgumentException("Invalid package");
+            }
+            NotificationChannel channel = r.channels.get(updatedChannel.getId());
+            if (channel == null || channel.isDeleted()) {
+                throw new IllegalArgumentException("Channel does not exist");
+            }
+            if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
+                updatedChannel.setLockscreenVisibility(
+                        NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
+            }
+            if (fromUser) {
+                updatedChannel.lockFields(channel.getUserLockedFields());
+                lockFieldsForUpdateLocked(channel, updatedChannel);
+            } 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());
+            }
+            updatedChannel.setImportanceLockedByCriticalDeviceFunction(
+                    r.defaultAppLockedImportance);
+            if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) {
+                updatedChannel.setImportance(channel.getImportance());
+            }
 
-        r.channels.put(updatedChannel.getId(), updatedChannel);
+            r.channels.put(updatedChannel.getId(), updatedChannel);
 
-        if (onlyHasDefaultChannel(pkg, uid)) {
-            // copy settings to app level so they are inherited by new channels
-            // when the app migrates
-            r.importance = updatedChannel.getImportance();
-            r.priority = updatedChannel.canBypassDnd()
-                    ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
-            r.visibility = updatedChannel.getLockscreenVisibility();
-            r.showBadge = updatedChannel.canShowBadge();
-        }
+            if (onlyHasDefaultChannel(pkg, uid)) {
+                // copy settings to app level so they are inherited by new channels
+                // when the app migrates
+                r.importance = updatedChannel.getImportance();
+                r.priority = updatedChannel.canBypassDnd()
+                        ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
+                r.visibility = updatedChannel.getLockscreenVisibility();
+                r.showBadge = updatedChannel.canShowBadge();
+            }
 
-        if (!channel.equals(updatedChannel)) {
-            // only log if there are real changes
-            MetricsLogger.action(getChannelLog(updatedChannel, pkg)
-                    .setSubtype(fromUser ? 1 : 0));
-        }
+            if (!channel.equals(updatedChannel)) {
+                // only log if there are real changes
+                MetricsLogger.action(getChannelLog(updatedChannel, pkg)
+                        .setSubtype(fromUser ? 1 : 0));
+            }
 
-        if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
-                || channel.getImportance() != updatedChannel.getImportance()) {
-            updateChannelsBypassingDnd(mContext.getUserId());
+            if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
+                    || channel.getImportance() != updatedChannel.getImportance()) {
+                updateChannelsBypassingDnd(mContext.getUserId());
+            }
         }
         updateConfig();
     }
@@ -745,35 +767,39 @@
     public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId,
             boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return null;
+            }
+            if (channelId == null) {
+                channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
+            }
+            final NotificationChannel nc = r.channels.get(channelId);
+            if (nc != null && (includeDeleted || !nc.isDeleted())) {
+                return nc;
+            }
             return null;
         }
-        if (channelId == null) {
-            channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
-        }
-        final NotificationChannel nc = r.channels.get(channelId);
-        if (nc != null && (includeDeleted || !nc.isDeleted())) {
-            return nc;
-        }
-        return null;
     }
 
     @Override
     public void deleteNotificationChannel(String pkg, int uid, String channelId) {
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return;
-        }
-        NotificationChannel channel = r.channels.get(channelId);
-        if (channel != null) {
-            channel.setDeleted(true);
-            LogMaker lm = getChannelLog(channel, pkg);
-            lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
-            MetricsLogger.action(lm);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return;
+            }
+            NotificationChannel channel = r.channels.get(channelId);
+            if (channel != null) {
+                channel.setDeleted(true);
+                LogMaker lm = getChannelLog(channel, pkg);
+                lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
+                MetricsLogger.action(lm);
 
-            if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
-                updateChannelsBypassingDnd(mContext.getUserId());
+                if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
+                    updateChannelsBypassingDnd(mContext.getUserId());
+                }
             }
         }
     }
@@ -783,25 +809,29 @@
     public void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId) {
         Preconditions.checkNotNull(pkg);
         Preconditions.checkNotNull(channelId);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return;
+            }
+            r.channels.remove(channelId);
         }
-        r.channels.remove(channelId);
     }
 
     @Override
     public void permanentlyDeleteNotificationChannels(String pkg, int uid) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return;
-        }
-        int N = r.channels.size() - 1;
-        for (int i = N; i >= 0; i--) {
-            String key = r.channels.keyAt(i);
-            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
-                r.channels.remove(key);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return;
+            }
+            int N = r.channels.size() - 1;
+            for (int i = N; i >= 0; i--) {
+                String key = r.channels.keyAt(i);
+                if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
+                    r.channels.remove(key);
+                }
             }
         }
     }
@@ -875,32 +905,36 @@
     public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
             int uid, String groupId, boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null || groupId == null || !r.groups.containsKey(groupId)) {
-            return null;
-        }
-        NotificationChannelGroup group = r.groups.get(groupId).clone();
-        group.setChannels(new ArrayList<>());
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (includeDeleted || !nc.isDeleted()) {
-                if (groupId.equals(nc.getGroup())) {
-                    group.addChannel(nc);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null || groupId == null || !r.groups.containsKey(groupId)) {
+                return null;
+            }
+            NotificationChannelGroup group = r.groups.get(groupId).clone();
+            group.setChannels(new ArrayList<>());
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (includeDeleted || !nc.isDeleted()) {
+                    if (groupId.equals(nc.getGroup())) {
+                        group.addChannel(nc);
+                    }
                 }
             }
+            return group;
         }
-        return group;
     }
 
     public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg,
             int uid) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return null;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return null;
+            }
+            return r.groups.get(groupId);
         }
-        return r.groups.get(groupId);
     }
 
     @Override
@@ -908,60 +942,64 @@
             int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
         Preconditions.checkNotNull(pkg);
         Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return ParceledListSlice.emptyList();
-        }
-        NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (includeDeleted || !nc.isDeleted()) {
-                if (nc.getGroup() != null) {
-                    if (r.groups.get(nc.getGroup()) != null) {
-                        NotificationChannelGroup ncg = groups.get(nc.getGroup());
-                        if (ncg == null) {
-                            ncg = r.groups.get(nc.getGroup()).clone();
-                            ncg.setChannels(new ArrayList<>());
-                            groups.put(nc.getGroup(), ncg);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return ParceledListSlice.emptyList();
+            }
+            NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (includeDeleted || !nc.isDeleted()) {
+                    if (nc.getGroup() != null) {
+                        if (r.groups.get(nc.getGroup()) != null) {
+                            NotificationChannelGroup ncg = groups.get(nc.getGroup());
+                            if (ncg == null) {
+                                ncg = r.groups.get(nc.getGroup()).clone();
+                                ncg.setChannels(new ArrayList<>());
+                                groups.put(nc.getGroup(), ncg);
 
+                            }
+                            ncg.addChannel(nc);
                         }
-                        ncg.addChannel(nc);
+                    } else {
+                        nonGrouped.addChannel(nc);
                     }
-                } else {
-                    nonGrouped.addChannel(nc);
                 }
             }
-        }
-        if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
-            groups.put(null, nonGrouped);
-        }
-        if (includeEmpty) {
-            for (NotificationChannelGroup group : r.groups.values()) {
-                if (!groups.containsKey(group.getId())) {
-                    groups.put(group.getId(), group);
+            if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
+                groups.put(null, nonGrouped);
+            }
+            if (includeEmpty) {
+                for (NotificationChannelGroup group : r.groups.values()) {
+                    if (!groups.containsKey(group.getId())) {
+                        groups.put(group.getId(), group);
+                    }
                 }
             }
+            return new ParceledListSlice<>(new ArrayList<>(groups.values()));
         }
-        return new ParceledListSlice<>(new ArrayList<>(groups.values()));
     }
 
     public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid,
             String groupId) {
         List<NotificationChannel> deletedChannels = new ArrayList<>();
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null || TextUtils.isEmpty(groupId)) {
-            return deletedChannels;
-        }
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null || TextUtils.isEmpty(groupId)) {
+                return deletedChannels;
+            }
 
-        r.groups.remove(groupId);
+            r.groups.remove(groupId);
 
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (groupId.equals(nc.getGroup())) {
-                nc.setDeleted(true);
-                deletedChannels.add(nc);
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (groupId.equals(nc.getGroup())) {
+                    nc.setDeleted(true);
+                    deletedChannels.add(nc);
+                }
             }
         }
         return deletedChannels;
@@ -970,11 +1008,15 @@
     @Override
     public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
             int uid) {
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return new ArrayList<>();
+        List<NotificationChannelGroup> groups = new ArrayList<>();
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return groups;
+            }
+            groups.addAll(r.groups.values());
         }
-        return r.groups.values();
+        return groups;
     }
 
     @Override
@@ -982,18 +1024,20 @@
             boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
         List<NotificationChannel> channels = new ArrayList<>();
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return ParceledListSlice.emptyList();
-        }
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (includeDeleted || !nc.isDeleted()) {
-                channels.add(nc);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return ParceledListSlice.emptyList();
             }
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (includeDeleted || !nc.isDeleted()) {
+                    channels.add(nc);
+                }
+            }
+            return new ParceledListSlice<>(channels);
         }
-        return new ParceledListSlice<>(channels);
     }
 
     /**
@@ -1008,7 +1052,7 @@
             // notifications from this package aren't blocked
             if (r != null && r.importance != IMPORTANCE_NONE) {
                 for (NotificationChannel channel : r.channels.values()) {
-                    if (channelIsLive(r, channel) && channel.canBypassDnd()) {
+                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                         channels.add(channel);
                     }
                 }
@@ -1024,46 +1068,52 @@
      * upgrades.
      */
     public boolean onlyHasDefaultChannel(String pkg, int uid) {
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r.channels.size() == 1
-                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            return true;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r.channels.size() == 1
+                    && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+                return true;
+            }
+            return false;
         }
-        return false;
     }
 
     public int getDeletedChannelCount(String pkg, int uid) {
         Preconditions.checkNotNull(pkg);
         int deletedCount = 0;
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return deletedCount;
+            }
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (nc.isDeleted()) {
+                    deletedCount++;
+                }
+            }
             return deletedCount;
         }
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (nc.isDeleted()) {
-                deletedCount++;
-            }
-        }
-        return deletedCount;
     }
 
     public int getBlockedChannelCount(String pkg, int uid) {
         Preconditions.checkNotNull(pkg);
         int blockedCount = 0;
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return blockedCount;
+            }
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (!nc.isDeleted() && IMPORTANCE_NONE == nc.getImportance()) {
+                    blockedCount++;
+                }
+            }
             return blockedCount;
         }
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (!nc.isDeleted() && IMPORTANCE_NONE == nc.getImportance()) {
-                blockedCount++;
-            }
-        }
-        return blockedCount;
     }
 
     public int getBlockedAppCount(int userId) {
@@ -1098,7 +1148,7 @@
                 }
 
                 for (NotificationChannel channel : r.channels.values()) {
-                    if (channelIsLive(r, channel) && channel.canBypassDnd()) {
+                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                         count++;
                         break;
                     }
@@ -1136,7 +1186,7 @@
                 }
 
                 for (NotificationChannel channel : r.channels.values()) {
-                    if (channelIsLive(r, channel) && channel.canBypassDnd()) {
+                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                         if (!mAreChannelsBypassingDnd) {
                             mAreChannelsBypassingDnd = true;
                             updateZenPolicy(true);
@@ -1153,7 +1203,7 @@
         }
     }
 
-    private boolean channelIsLive(PackagePreferences pkgPref, NotificationChannel channel) {
+    private boolean channelIsLiveLocked(PackagePreferences pkgPref, NotificationChannel channel) {
         // Channel is in a group that's blocked
         if (isGroupBlocked(pkgPref.pkg, pkgPref.uid, channel.getGroup())) {
             return false;
@@ -1185,7 +1235,9 @@
      */
     @Override
     public void setImportance(String pkgName, int uid, int importance) {
-        getOrCreatePackagePreferences(pkgName, uid).importance = importance;
+        synchronized (mPackagePreferences) {
+            getOrCreatePackagePreferencesLocked(pkgName, uid).importance = importance;
+        }
         updateConfig();
     }
 
@@ -1204,12 +1256,15 @@
      * considered for sentiment adjustments (and thus never show a blocking helper).
      */
     public void setAppImportanceLocked(String packageName, int uid) {
-        PackagePreferences prefs = getOrCreatePackagePreferences(packageName, uid);
-        if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
-            return;
-        }
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getOrCreatePackagePreferencesLocked(packageName, uid);
+            if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
+                return;
+            }
 
-        prefs.lockedAppFields = prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
+            prefs.lockedAppFields =
+                    prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
+        }
         updateConfig();
     }
 
@@ -1217,15 +1272,17 @@
      * Returns the delegate for a given package, if it's allowed by the package and the user.
      */
     public @Nullable String getNotificationDelegate(String sourcePkg, int sourceUid) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
 
-        if (prefs == null || prefs.delegate == null) {
-            return null;
+            if (prefs == null || prefs.delegate == null) {
+                return null;
+            }
+            if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) {
+                return null;
+            }
+            return prefs.delegate.mPkg;
         }
-        if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) {
-            return null;
-        }
-        return prefs.delegate.mPkg;
     }
 
     /**
@@ -1233,11 +1290,13 @@
      */
     public void setNotificationDelegate(String sourcePkg, int sourceUid,
             String delegatePkg, int delegateUid) {
-        PackagePreferences prefs = getOrCreatePackagePreferences(sourcePkg, sourceUid);
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getOrCreatePackagePreferencesLocked(sourcePkg, sourceUid);
 
-        boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed;
-        Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed);
-        prefs.delegate = delegate;
+            boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed;
+            Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed);
+            prefs.delegate = delegate;
+        }
         updateConfig();
     }
 
@@ -1245,9 +1304,15 @@
      * Used by an app to turn off its notification delegate.
      */
     public void revokeNotificationDelegate(String sourcePkg, int sourceUid) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
-        if (prefs != null && prefs.delegate != null) {
-            prefs.delegate.mEnabled = false;
+        boolean changed = false;
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
+            if (prefs != null && prefs.delegate != null) {
+                prefs.delegate.mEnabled = false;
+                changed = true;
+            }
+        }
+        if (changed) {
             updateConfig();
         }
     }
@@ -1256,9 +1321,15 @@
      * Toggles whether an app can have a notification delegate on behalf of a user.
      */
     public void toggleNotificationDelegate(String sourcePkg, int sourceUid, boolean userAllowed) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
-        if (prefs != null && prefs.delegate != null) {
-            prefs.delegate.mUserAllowed = userAllowed;
+        boolean changed = false;
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
+            if (prefs != null && prefs.delegate != null) {
+                prefs.delegate.mUserAllowed = userAllowed;
+                changed = true;
+            }
+        }
+        if (changed) {
             updateConfig();
         }
     }
@@ -1269,13 +1340,16 @@
      */
     public boolean isDelegateAllowed(String sourcePkg, int sourceUid,
             String potentialDelegatePkg, int potentialDelegateUid) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
 
-        return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, potentialDelegateUid);
+            return prefs != null && prefs.isValidDelegate(potentialDelegatePkg,
+                    potentialDelegateUid);
+        }
     }
 
     @VisibleForTesting
-    void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
+    void lockFieldsForUpdateLocked(NotificationChannel original, NotificationChannel update) {
         if (original.canBypassDnd() != update.canBypassDnd()) {
             update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
         }
@@ -1309,30 +1383,30 @@
         pw.print(prefix);
         pw.println("per-package config:");
 
-        pw.println("PackagePreferencess:");
+        pw.println("PackagePreferences:");
         synchronized (mPackagePreferences) {
-            dumpPackagePreferencess(pw, prefix, filter, mPackagePreferences);
+            dumpPackagePreferencesLocked(pw, prefix, filter, mPackagePreferences);
         }
         pw.println("Restored without uid:");
-        dumpPackagePreferencess(pw, prefix, filter, mRestoredWithoutUids);
+        dumpPackagePreferencesLocked(pw, prefix, filter, mRestoredWithoutUids);
     }
 
     public void dump(ProtoOutputStream proto,
             @NonNull NotificationManagerService.DumpFilter filter) {
         synchronized (mPackagePreferences) {
-            dumpPackagePreferencess(proto, RankingHelperProto.RECORDS, filter,
+            dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS, filter,
                     mPackagePreferences);
         }
-        dumpPackagePreferencess(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter,
+        dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter,
                 mRestoredWithoutUids);
     }
 
-    private static void dumpPackagePreferencess(PrintWriter pw, String prefix,
+    private static void dumpPackagePreferencesLocked(PrintWriter pw, String prefix,
             @NonNull NotificationManagerService.DumpFilter filter,
-            ArrayMap<String, PackagePreferences> PackagePreferencess) {
-        final int N = PackagePreferencess.size();
+            ArrayMap<String, PackagePreferences> packagePreferences) {
+        final int N = packagePreferences.size();
         for (int i = 0; i < N; i++) {
-            final PackagePreferences r = PackagePreferencess.valueAt(i);
+            final PackagePreferences r = packagePreferences.valueAt(i);
             if (filter.matches(r.pkg)) {
                 pw.print(prefix);
                 pw.print("  AppSettings: ");
@@ -1369,13 +1443,13 @@
         }
     }
 
-    private static void dumpPackagePreferencess(ProtoOutputStream proto, long fieldId,
+    private static void dumpPackagePreferencesLocked(ProtoOutputStream proto, long fieldId,
             @NonNull NotificationManagerService.DumpFilter filter,
-            ArrayMap<String, PackagePreferences> PackagePreferencess) {
-        final int N = PackagePreferencess.size();
+            ArrayMap<String, PackagePreferences> packagePreferences) {
+        final int N = packagePreferences.size();
         long fToken;
         for (int i = 0; i < N; i++) {
-            final PackagePreferences r = PackagePreferencess.valueAt(i);
+            final PackagePreferences r = packagePreferences.valueAt(i);
             if (filter.matches(r.pkg)) {
                 fToken = proto.start(fieldId);
 
@@ -1626,11 +1700,11 @@
                 // Package upgrade
                 try {
                     synchronized (mPackagePreferences) {
-                        PackagePreferences fullPackagePreferences = getPackagePreferences(pkg,
+                        PackagePreferences fullPackagePreferences = getPackagePreferencesLocked(pkg,
                                 mPm.getPackageUidAsUser(pkg, changeUserId));
                         if (fullPackagePreferences != null) {
-                            createDefaultChannelIfNeeded(fullPackagePreferences);
-                            deleteDefaultChannelIfNeeded(fullPackagePreferences);
+                            createDefaultChannelIfNeededLocked(fullPackagePreferences);
+                            deleteDefaultChannelIfNeededLocked(fullPackagePreferences);
                         }
                     }
                 } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index ea7bf2d2..7e74cc2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -389,8 +389,8 @@
             if (mConfig == null) return;
 
             newConfig = mConfig.copy();
+            setAutomaticZenRuleStateLocked(newConfig, newConfig.automaticRules.get(id), condition);
         }
-        setAutomaticZenRuleState(newConfig, newConfig.automaticRules.get(id), condition);
     }
 
     public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition) {
@@ -398,14 +398,15 @@
         synchronized (mConfig) {
             if (mConfig == null) return;
             newConfig = mConfig.copy();
-        }
 
-        setAutomaticZenRuleState(newConfig,
-                findMatchingRule(newConfig, ruleDefinition, condition),
-                condition);
+            setAutomaticZenRuleStateLocked(newConfig,
+                    findMatchingRule(newConfig, ruleDefinition, condition),
+                    condition);
+        }
     }
 
-    private void setAutomaticZenRuleState(ZenModeConfig config, ZenRule rule, Condition condition) {
+    private void setAutomaticZenRuleStateLocked(ZenModeConfig config, ZenRule rule,
+            Condition condition) {
         if (rule == null) return;
 
         rule.condition = condition;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 51d5acc..ee07c7d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -166,6 +166,13 @@
  *     . . . .  . . . . . . . . . . . . . . . . . .
  * </pre>
  *
+ * <p>To test the OMS, execute:
+ * <code>
+ * atest FrameworksServicesTests:com.android.server.om  # internal tests
+ * atest OverlayDeviceTests OverlayHostTests            # public API tests
+ * </code>
+ * </p>
+ *
  * <p>Finally, here is a list of keywords used in the OMS context.</p>
  *
  * <ul>
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 36b5beb..f35c707 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -26,6 +26,7 @@
 import android.util.Slog;
 import android.util.Xml;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
@@ -327,7 +328,8 @@
         Serializer.persist(mItems, os);
     }
 
-    private static final class Serializer {
+    @VisibleForTesting
+    static final class Serializer {
         private static final String TAG_OVERLAYS = "overlays";
         private static final String TAG_ITEM = "item";
 
@@ -343,7 +345,8 @@
         private static final String ATTR_USER_ID = "userId";
         private static final String ATTR_VERSION = "version";
 
-        private static final int CURRENT_VERSION = 3;
+        @VisibleForTesting
+        static final int CURRENT_VERSION = 3;
 
         public static void restore(@NonNull final ArrayList<SettingsItem> table,
                 @NonNull final InputStream is) throws IOException, XmlPullParserException {
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 944aef5..21b6f12 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -324,6 +324,8 @@
                     ipw.println("State: ROLLBACK IN PROGRESS");
                 } else if (si.isRolledBack) {
                     ipw.println("State: ROLLED BACK");
+                } else if (si.isRollbackFailed) {
+                    ipw.println("State: ROLLBACK FAILED");
                 }
                 ipw.decreaseIndent();
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 51bf519..d3aa746 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2967,7 +2967,7 @@
 
                 // Uncompress and install any stubbed system applications.
                 // This must be done last to ensure all stubs are replaced or disabled.
-                decompressSystemApplications(stubSystemApps, scanFlags);
+                installSystemStubPackages(stubSystemApps, scanFlags);
 
                 final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get()
                                 - cachedSystemApps;
@@ -3051,7 +3051,7 @@
                         + mSdkVersion + "; regranting permissions for internal storage");
             }
             mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, false, mPackages.values(),
+                    StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
                     mPermissionCallback);
             ver.sdkVersion = mSdkVersion;
 
@@ -3278,49 +3278,37 @@
      * <p>In order to forcefully attempt an installation of a full application, go to app
      * settings and enable the application.
      */
-    private void decompressSystemApplications(@NonNull List<String> stubSystemApps, int scanFlags) {
-        for (int i = stubSystemApps.size() - 1; i >= 0; --i) {
-            final String pkgName = stubSystemApps.get(i);
+    private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
+            @ScanFlags int scanFlags) {
+        for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+            final String packageName = systemStubPackageNames.get(i);
             // skip if the system package is already disabled
-            if (mSettings.isDisabledSystemPackageLPr(pkgName)) {
-                stubSystemApps.remove(i);
+            if (mSettings.isDisabledSystemPackageLPr(packageName)) {
+                systemStubPackageNames.remove(i);
                 continue;
             }
             // skip if the package isn't installed (?!); this should never happen
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null) {
-                stubSystemApps.remove(i);
+                systemStubPackageNames.remove(i);
                 continue;
             }
             // skip if the package has been disabled by the user
-            final PackageSetting ps = mSettings.mPackages.get(pkgName);
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps != null) {
                 final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
                 if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
-                    stubSystemApps.remove(i);
+                    systemStubPackageNames.remove(i);
                     continue;
                 }
             }
 
-            if (DEBUG_COMPRESSION) {
-                Slog.i(TAG, "Uncompressing system stub; pkg: " + pkgName);
-            }
-
-            // uncompress the binary to its eventual destination on /data
-            final File scanFile = decompressPackage(pkg);
-            if (scanFile == null) {
-                continue;
-            }
-
             // install the package to replace the stub on /system
             try {
-                mSettings.disableSystemPackageLPw(pkgName, true /*replaced*/);
-                removePackageLI(pkg, true /*chatty*/);
-                scanPackageTracedLI(scanFile, 0 /*reparseFlags*/, scanFlags, 0, null);
+                installStubPackageLI(pkg, 0, scanFlags);
                 ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
                         UserHandle.USER_SYSTEM, "android");
-                stubSystemApps.remove(i);
-                continue;
+                systemStubPackageNames.remove(i);
             } catch (PackageManagerException e) {
                 Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
             }
@@ -3329,8 +3317,8 @@
         }
 
         // disable any stub still left; these failed to install the full application
-        for (int i = stubSystemApps.size() - 1; i >= 0; --i) {
-            final String pkgName = stubSystemApps.get(i);
+        for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+            final String pkgName = systemStubPackageNames.get(i);
             final PackageSetting ps = mSettings.mPackages.get(pkgName);
             ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                     UserHandle.USER_SYSTEM, "android");
@@ -3339,20 +3327,107 @@
     }
 
     /**
+     * Extract, install and enable a stub package.
+     * <p>If the compressed file can not be extracted / installed for any reason, the stub
+     * APK will be installed and the package will be disabled. To recover from this situation,
+     * the user will need to go into system settings and re-enable the package.
+     */
+    private boolean enableCompressedPackage(PackageParser.Package stubPkg) {
+        final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+                | PackageParser.PARSE_ENFORCE_CODE;
+        synchronized (mInstallLock) {
+            final PackageParser.Package pkg;
+            try (PackageFreezer freezer =
+                    freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+                pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
+                synchronized (mPackages) {
+                    prepareAppDataAfterInstallLIF(pkg);
+                    try {
+                        updateSharedLibrariesLocked(pkg, null, mPackages);
+                    } catch (PackageManagerException e) {
+                        Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
+                    }
+                    mPermissionManager.updatePermissions(
+                            pkg.packageName, pkg, true, mPackages.values(),
+                            mPermissionCallback);
+                    mSettings.writeLPr();
+                }
+            } catch (PackageManagerException e) {
+                // Whoops! Something went very wrong; roll back to the stub and disable the package
+                try (PackageFreezer freezer =
+                        freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+                    synchronized (mPackages) {
+                        // NOTE: Ensure the system package is enabled; even for a compressed stub.
+                        // If we don't, installing the system package fails during scan
+                        enableSystemPackageLPw(stubPkg);
+                    }
+                    installPackageFromSystemLIF(stubPkg.codePath,
+                            null /*allUserHandles*/, null /*origUserHandles*/,
+                            null /*origPermissionsState*/, true /*writeSettings*/);
+                } catch (PackageManagerException pme) {
+                    // Serious WTF; we have to be able to install the stub
+                    Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme);
+                } finally {
+                    // Disable the package; the stub by itself is not runnable
+                    synchronized (mPackages) {
+                        final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+                        if (stubPs != null) {
+                            stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
+                                    UserHandle.USER_SYSTEM, "android");
+                        }
+                        mSettings.writeLPr();
+                    }
+                }
+                return false;
+            }
+            clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
+                    | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+            mDexManager.notifyPackageUpdated(pkg.packageName,
+                    pkg.baseCodePath, pkg.splitCodePaths);
+        }
+        return true;
+    }
+
+    private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg,
+            @ParseFlags int parseFlags, @ScanFlags int scanFlags)
+                    throws PackageManagerException {
+        if (DEBUG_COMPRESSION) {
+            Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName);
+        }
+        // uncompress the binary to its eventual destination on /data
+        final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath);
+        if (scanFile == null) {
+            throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath);
+        }
+        synchronized (mPackages) {
+            mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/);
+        }
+        removePackageLI(stubPkg, true /*chatty*/);
+        try {
+            return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+        } catch (PackageManagerException e) {
+            Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e);
+            // Remove the failed install
+            removeCodePathLI(scanFile);
+            throw e;
+        }
+    }
+
+    /**
      * Decompresses the given package on the system image onto
      * the /data partition.
      * @return The directory the package was decompressed into. Otherwise, {@code null}.
      */
-    private File decompressPackage(PackageParser.Package pkg) {
-        final File[] compressedFiles = getCompressedFiles(pkg.codePath);
+    private File decompressPackage(String packageName, String codePath) {
+        final File[] compressedFiles = getCompressedFiles(codePath);
         if (compressedFiles == null || compressedFiles.length == 0) {
             if (DEBUG_COMPRESSION) {
-                Slog.i(TAG, "No files to decompress: " + pkg.baseCodePath);
+                Slog.i(TAG, "No files to decompress: " + codePath);
             }
             return null;
         }
         final File dstCodePath =
-                getNextCodePath(Environment.getDataAppDirectory(null), pkg.packageName);
+                getNextCodePath(Environment.getDataAppDirectory(null), packageName);
         int ret = PackageManager.INSTALL_SUCCEEDED;
         try {
             Os.mkdir(dstCodePath.getAbsolutePath(), 0755);
@@ -3365,14 +3440,14 @@
                 ret = decompressFile(srcFile, dstFile);
                 if (ret != PackageManager.INSTALL_SUCCEEDED) {
                     logCriticalInfo(Log.ERROR, "Failed to decompress"
-                            + "; pkg: " + pkg.packageName
+                            + "; pkg: " + packageName
                             + ", file: " + dstFileName);
                     break;
                 }
             }
         } catch (ErrnoException e) {
             logCriticalInfo(Log.ERROR, "Failed to decompress"
-                    + "; pkg: " + pkg.packageName
+                    + "; pkg: " + packageName
                     + ", err: " + e.errno);
         }
         if (ret == PackageManager.INSTALL_SUCCEEDED) {
@@ -3384,7 +3459,7 @@
                         null /*abiOverride*/);
             } catch (IOException e) {
                 logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
-                        + "; pkg: " + pkg.packageName);
+                        + "; pkg: " + packageName);
                 ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
             } finally {
                 IoUtils.closeQuietly(handle);
@@ -5569,7 +5644,7 @@
 
         synchronized (mPackages) {
             mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, false, false, mPackages.values(),
+                    StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
                     mPermissionCallback);
             for (int userId : UserManagerService.getInstance().getUserIds()) {
                 final int packageCount = mPackages.size();
@@ -18216,12 +18291,15 @@
             return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
         }
 
-        PackageSetting uninstalledPs;
-        PackageParser.Package pkg;
+        final PackageSetting uninstalledPs;
+        final PackageSetting disabledSystemPs;
+        final PackageParser.Package pkg;
 
         // for the uninstall-updates case and restricted profiles, remember the per-
         // user handle installed state
         int[] allUsers;
+        /** enabled state of the uninstalled application */
+        final int origEnabledState;
         synchronized (mPackages) {
             uninstalledPs = mSettings.mPackages.get(packageName);
             if (uninstalledPs == null) {
@@ -18236,6 +18314,11 @@
                 return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
             }
 
+            disabledSystemPs = mSettings.getDisabledSystemPkgLPr(packageName);
+            // Save the enabled state before we delete the package. When deleting a stub
+            // application we always set the enabled state to 'disabled'.
+            origEnabledState = uninstalledPs == null
+                    ? COMPONENT_ENABLED_STATE_DEFAULT : uninstalledPs.getEnabled(userId);
             // Static shared libs can be declared by any package, so let us not
             // allow removing a package if it provides a lib others depend on.
             pkg = mPackages.get(packageName);
@@ -18304,10 +18387,30 @@
         Runtime.getRuntime().gc();
         // Delete the resources here after sending the broadcast to let
         // other processes clean up before deleting resources.
-        if (info.args != null) {
-            synchronized (mInstallLock) {
+        synchronized (mInstallLock) {
+            if (info.args != null) {
                 info.args.doPostDeleteLI(true);
             }
+            final PackageParser.Package stubPkg =
+                    (disabledSystemPs == null) ? null : disabledSystemPs.pkg;
+            if (stubPkg != null && stubPkg.isStub) {
+                synchronized (mPackages) {
+                    // restore the enabled state of the stub; the state is overwritten when
+                    // the stub is uninstalled
+                    final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+                    if (stubPs != null) {
+                        stubPs.setEnabled(origEnabledState, userId, "android");
+                    }
+                }
+                if (origEnabledState == COMPONENT_ENABLED_STATE_DEFAULT
+                        || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
+                    if (DEBUG_COMPRESSION) {
+                        Slog.i(TAG, "Enabling system stub after removal; pkg: "
+                                + stubPkg.packageName);
+                    }
+                    enableCompressedPackage(stubPkg);
+                }
+            }
         }
 
         return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
@@ -18713,7 +18816,14 @@
             throw new SystemDeleteException(e);
         } finally {
             if (disabledPs.pkg.isStub) {
-                mSettings.disableSystemPackageLPw(disabledPs.name, true /*replaced*/);
+                // We've re-installed the stub; make sure it's disabled here. If package was
+                // originally enabled, we'll install the compressed version of the application
+                // and re-enable it afterward.
+                final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName);
+                if (stubPs != null) {
+                    stubPs.setEnabled(
+                            COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
+                }
             }
         }
     }
@@ -20798,102 +20908,9 @@
             if (isSystemStub
                     && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                             || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
-                final File codePath = decompressPackage(deletedPkg);
-                if (codePath == null) {
-                    Slog.e(TAG, "couldn't decompress pkg: " + pkgSetting.name);
+                if (!enableCompressedPackage(deletedPkg)) {
                     return;
                 }
-                // TODO remove direct parsing of the package object during internal cleanup
-                // of scan package
-                // We need to call parse directly here for no other reason than we need
-                // the new package in order to disable the old one [we use the information
-                // for some internal optimization to optionally create a new package setting
-                // object on replace]. However, we can't get the package from the scan
-                // because the scan modifies live structures and we need to remove the
-                // old [system] package from the system before a scan can be attempted.
-                // Once scan is indempotent we can remove this parse and use the package
-                // object we scanned, prior to adding it to package settings.
-                final PackageParser pp = new PackageParser();
-                pp.setSeparateProcesses(mSeparateProcesses);
-                pp.setDisplayMetrics(mMetrics);
-                pp.setCallback(mPackageParserCallback);
-                final PackageParser.Package tmpPkg;
-                try {
-                    final @ParseFlags int parseFlags = mDefParseFlags
-                            | PackageParser.PARSE_MUST_BE_APK
-                            | PackageParser.PARSE_IS_SYSTEM_DIR;
-                    tmpPkg = pp.parsePackage(codePath, parseFlags);
-                } catch (PackageParserException e) {
-                    Slog.w(TAG, "Failed to parse compressed system package:" + pkgSetting.name, e);
-                    return;
-                }
-                synchronized (mInstallLock) {
-                    // Disable the stub and remove any package entries
-                    removePackageLI(deletedPkg, true);
-                    synchronized (mPackages) {
-                        disableSystemPackageLPw(deletedPkg, tmpPkg);
-                    }
-                    final PackageParser.Package pkg;
-                    try (PackageFreezer freezer =
-                            freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
-                        final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
-                                | PackageParser.PARSE_ENFORCE_CODE;
-                        pkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/,
-                                0 /*currentTime*/, null /*user*/);
-                        prepareAppDataAfterInstallLIF(pkg);
-                        synchronized (mPackages) {
-                            try {
-                                updateSharedLibrariesLocked(pkg, null, mPackages);
-                            } catch (PackageManagerException e) {
-                                Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
-                            }
-                            mPermissionManager.updatePermissions(
-                                    pkg.packageName, pkg, true, mPackages.values(),
-                                    mPermissionCallback);
-                            mSettings.writeLPr();
-                        }
-                    } catch (PackageManagerException e) {
-                        // Whoops! Something went wrong; try to roll back to the stub
-                        Slog.w(TAG, "Failed to install compressed system package:"
-                                + pkgSetting.name, e);
-                        // Remove the failed install
-                        removeCodePathLI(codePath);
-
-                        // Install the system package
-                        try (PackageFreezer freezer =
-                                freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
-                            synchronized (mPackages) {
-                                // NOTE: The system package always needs to be enabled; even
-                                // if it's for a compressed stub. If we don't, installing the
-                                // system package fails during scan [scanning checks the disabled
-                                // packages]. We will reverse this later, after we've "installed"
-                                // the stub.
-                                // This leaves us in a fragile state; the stub should never be
-                                // enabled, so, cross your fingers and hope nothing goes wrong
-                                // until we can disable the package later.
-                                enableSystemPackageLPw(deletedPkg);
-                            }
-                            installPackageFromSystemLIF(deletedPkg.codePath,
-                                    /*isPrivileged*/ null /*allUserHandles*/,
-                                    null /*origUserHandles*/, null /*origPermissionsState*/,
-                                    true /*writeSettings*/);
-                        } catch (PackageManagerException pme) {
-                            Slog.w(TAG, "Failed to restore system package:"
-                                    + deletedPkg.packageName, pme);
-                        } finally {
-                            synchronized (mPackages) {
-                                mSettings.disableSystemPackageLPw(
-                                        deletedPkg.packageName, true /*replaced*/);
-                                mSettings.writeLPr();
-                            }
-                        }
-                        return;
-                    }
-                    clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
-                            | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-                    mDexManager.notifyPackageUpdated(pkg.packageName,
-                            pkg.baseCodePath, pkg.splitCodePaths);
-                }
             }
             if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                 || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
@@ -21222,8 +21239,8 @@
         // try optimizing this.
         synchronized (mPackages) {
             mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, false, mIsPreQUpgrade,
-                    mPackages.values(), mPermissionCallback);
+                    StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
+                    mPermissionCallback);
         }
 
         // Watch for external volumes that come and go over time
@@ -22213,8 +22230,8 @@
                 logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
                         + mSdkVersion + "; regranting permissions for " + volumeUuid);
             }
-            mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, false,
-                    mPackages.values(), mPermissionCallback);
+            mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, mPackages.values(),
+                    mPermissionCallback);
 
             // Yay, everything is now upgraded
             ver.forceCurrent();
@@ -23247,7 +23264,7 @@
         synchronized(mPackages) {
             // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
             mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, true, false, mPackages.values(),
+                    StorageManager.UUID_PRIVATE_INTERNAL, true, mPackages.values(),
                     mPermissionCallback);
         }
     }
@@ -24816,11 +24833,9 @@
         }
         if (mExternalSourcesPolicy != null) {
             int isTrusted = mExternalSourcesPolicy.getPackageTrustedToInstallApps(packageName, uid);
-            if (isTrusted != PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT) {
-                return isTrusted == PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
-            }
+            return isTrusted == PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
         }
-        return checkUidPermission(appOpPermission, uid) == PERMISSION_GRANTED;
+        return false;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index a0f0a31..1908b3f 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -565,7 +565,8 @@
         // isRollbackInProgress is included to cover the scenario, when a device is rebooted in
         // during the rollback, and apexd fails to resume the rollback after reboot.
         return apexSessionInfo.isActivationFailed || apexSessionInfo.isUnknown
-                || apexSessionInfo.isRolledBack || apexSessionInfo.isRollbackInProgress;
+                || apexSessionInfo.isRolledBack || apexSessionInfo.isRollbackInProgress
+                || apexSessionInfo.isRollbackFailed;
     }
 
     @GuardedBy("mStagedSessions")
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 5df2f86..108eaf6 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -108,7 +108,10 @@
 
     @PackageManager.PackageInfoFlags
     private static final int DEFAULT_PACKAGE_INFO_QUERY_FLAGS =
-            PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS;
+            PackageManager.MATCH_UNINSTALLED_PACKAGES
+                    | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                    | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                    | PackageManager.GET_PERMISSIONS;
 
     private static final String AUDIO_MIME_TYPE = "audio/mpeg";
 
@@ -302,6 +305,7 @@
     }
 
     public void grantDefaultPermissions(int userId) {
+        removeSystemFixedStorage(userId);
         grantPermissionsToSysComponentsAndPrivApps(userId);
         grantDefaultSystemHandlerPermissions(userId);
         grantDefaultPermissionExceptions(userId);
@@ -310,6 +314,46 @@
         }
     }
 
+    // STOPSHIP: This is meant to fix the devices messed up by storage permission model 2 and
+    //           should be removed once all devices were updated
+    private void removeSystemFixedStorage(int userId) {
+        List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser(
+                DEFAULT_PACKAGE_INFO_QUERY_FLAGS, userId);
+
+        for (PackageInfo pkg : packages) {
+            if (pkg == null || pkg.requestedPermissions == null) {
+                continue;
+            }
+
+            for (String permission : pkg.requestedPermissions) {
+                if (!(Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)
+                        || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission))) {
+                    continue;
+                }
+
+                int flags = mContext.getPackageManager().getPermissionFlags(permission,
+                        pkg.packageName, UserHandle.of(userId));
+                if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) == 0) {
+                    continue;
+                }
+
+                Log.v(TAG, "Removing system fixed " + pkg.packageName + "/" + permission);
+                mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+                        PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, UserHandle.of(userId));
+
+                if (!doesPackageSupportRuntimePermissions(pkg)
+                        || (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+                        | PackageManager.FLAG_PERMISSION_POLICY_FIXED)) != 0) {
+                    continue;
+                }
+
+                Log.v(TAG, "Revoking " + pkg.packageName + "/" + permission);
+                mContext.getPackageManager().revokeRuntimePermission(pkg.packageName, permission,
+                        UserHandle.of(userId));
+            }
+        }
+    }
+
     private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
         Set<String> permissions = new ArraySet<>();
         for (String permission : pkg.requestedPermissions) {
@@ -1312,8 +1356,7 @@
     }
 
     private PackageInfo getSystemPackageInfo(String pkg) {
-        //TODO not MATCH_SYSTEM_ONLY?
-        return getPackageInfo(pkg, PackageManager.MATCH_FACTORY_ONLY);
+        return getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY);
     }
 
     private PackageInfo getPackageInfo(String pkg) {
@@ -1322,6 +1365,9 @@
 
     private PackageInfo getPackageInfo(String pkg,
             @PackageManager.PackageInfoFlags int extraFlags) {
+        if (pkg == null) {
+            return null;
+        }
         try {
             return mContext.getPackageManager().getPackageInfo(pkg,
                     DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 9336c55..c75a462 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -34,10 +34,10 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE;
+import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
 import static android.content.pm.PackageManager.RESTRICTED_PERMISSIONS_ENABLED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.UserHandle.getAppId;
@@ -69,7 +69,6 @@
 import android.metrics.LogMaker;
 import android.os.Binder;
 import android.os.Build;
-import android.os.Debug;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
@@ -82,7 +81,6 @@
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.permission.PermissionManagerInternal;
-import android.provider.Settings;
 import android.permission.PermissionManagerInternal.OnRuntimePermissionStateChangedListener;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -2458,9 +2456,8 @@
         }
 
         if (updatePermissions) {
-            // Update app permissions to take into account the new whitelist state.
-            updatePermissions(pkg.packageName, pkg, getVolumeUuidForPackage(pkg),
-                    0 /*flags*/, null /*allPackages*/, callback);
+            // Update permission of this app to take into account the new whitelist state.
+            restorePermissionState(pkg, false, pkg.packageName, callback);
 
             // If this resulted in losing a permission we need to kill the app.
             if (oldGrantedRestrictedPermissions != null) {
@@ -2605,62 +2602,12 @@
     }
 
     private void updateAllPermissions(String volumeUuid, boolean sdkUpdated,
-            boolean updatePermissionsOnPreQUpdate, Collection<PackageParser.Package> allPackages,
-            PermissionCallback callback) {
+            Collection<PackageParser.Package> allPackages, PermissionCallback callback) {
         final int flags = UPDATE_PERMISSIONS_ALL |
                 (sdkUpdated
                         ? UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL
                         : 0);
         updatePermissions(null, null, volumeUuid, flags, allPackages, callback);
-
-        if (updatePermissionsOnPreQUpdate) {
-            final int[] userIds = UserManagerService.getInstance().getUserIds();
-
-            for (PackageParser.Package pkg : allPackages) {
-                final PackageSetting ps = (PackageSetting) pkg.mExtras;
-                if (ps == null) {
-                    return;
-                }
-
-                final boolean appSupportsRuntimePermissions =
-                        pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
-                final PermissionsState permsState = ps.getPermissionsState();
-
-                for (String permName : new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
-                        Manifest.permission.ACCESS_COARSE_LOCATION,
-                        Manifest.permission.ACCESS_BACKGROUND_LOCATION}) {
-                    final BasePermission bp = mSettings.getPermissionLocked(permName);
-
-                    for (int userId : userIds) {
-                        if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                                Settings.Secure.LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE, 0, userId)
-                                != 0) {
-                            continue;
-                        }
-
-                        final PermissionState permState = permsState.getRuntimePermissionState(
-                                permName, userId);
-
-                        if (permState != null
-                                && (permState.getFlags() & BLOCKING_PERMISSION_FLAGS) == 0) {
-                            if (permState.isGranted()) {
-                                permsState.updatePermissionFlags(bp, userId,
-                                        USER_PERMISSION_FLAGS, 0);
-                            }
-
-                            if (appSupportsRuntimePermissions) {
-                                permsState.revokeRuntimePermission(bp, userId);
-                            } else {
-                                // Force a review even for apps that were already installed
-                                permsState.updatePermissionFlags(bp, userId,
-                                        FLAG_PERMISSION_REVIEW_REQUIRED,
-                                        FLAG_PERMISSION_REVIEW_REQUIRED);
-                            }
-                        }
-                    }
-                }
-            }
-        }
     }
 
     private void updatePermissions(String changingPkgName, PackageParser.Package changingPkg,
@@ -3150,10 +3097,9 @@
         }
         @Override
         public void updateAllPermissions(String volumeUuid, boolean sdkUpdated,
-                boolean updatePermissionsOnPreQUpdate, Collection<PackageParser.Package> allPackages,
-                PermissionCallback callback) {
+                Collection<PackageParser.Package> allPackages, PermissionCallback callback) {
             PermissionManagerService.this.updateAllPermissions(
-                    volumeUuid, sdkUpdated, updatePermissionsOnPreQUpdate, allPackages, callback);
+                    volumeUuid, sdkUpdated, allPackages, callback);
         }
         @Override
         public String[] getAppOpPermissionPackages(String permName) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 34f922e..9fb71f4 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -93,7 +93,6 @@
             @Nullable PackageParser.Package pkg, boolean replaceGrant,
             @NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback);
     public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate,
-            boolean updatePermissionsOnPreQUpdate,
             @NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback);
 
     /**
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 3011808..67f30dc 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -22,25 +22,28 @@
 import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
+import android.os.Process;
 import android.os.UserHandle;
-import android.os.UserManagerInternal;
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManagerInternal;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.util.function.QuadConsumer;
-import com.android.internal.util.function.TriConsumer;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
 /**
@@ -51,11 +54,17 @@
  * and app ops - and vise versa.
  */
 public final class PermissionPolicyService extends SystemService {
+    private static final String PLATFORM_PACKAGE = "android";
 
     private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName();
 
+    // No need to lock as this is populated on boot when the OS is
+    // single threaded and is never mutated until a reboot.
+    private static final ArraySet<String> sAllRestrictedPermissions = new ArraySet<>();
+
     public PermissionPolicyService(@NonNull Context context) {
         super(context);
+        cacheAllRestrictedPermissions(context);
     }
 
     @Override
@@ -89,6 +98,20 @@
         startWatchingRuntimePermissionChanges(getContext(), userId);
     }
 
+    private static void cacheAllRestrictedPermissions(@NonNull Context context) {
+        try {
+            final PackageInfo packageInfo = context.getPackageManager()
+                    .getPackageInfo(PLATFORM_PACKAGE, PackageManager.GET_PERMISSIONS);
+            for (PermissionInfo permissionInfo : packageInfo.permissions) {
+                if (permissionInfo.isRestricted()) {
+                    sAllRestrictedPermissions.add(permissionInfo.name);
+                }
+            }
+        } catch (NameNotFoundException impossible) {
+            /* cannot happen */
+        }
+    }
+
     private static void grantOrUpgradeDefaultRuntimePermissionsInNeeded(@NonNull Context context,
             @UserIdInt int userId) {
         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
@@ -123,16 +146,6 @@
         }
     }
 
-    private static void onRestrictedPermissionEnabledChange(@NonNull Context context) {
-        final PermissionManagerInternal permissionManagerInternal = LocalServices
-                .getService(PermissionManagerInternal.class);
-        final UserManagerInternal userManagerInternal = LocalServices.getService(
-                UserManagerInternal.class);
-        for (int userId : userManagerInternal.getUserIds()) {
-            synchronizePermissionsAndAppOpsForUser(context, userId);
-        }
-    }
-
     private static void startWatchingRuntimePermissionChanges(@NonNull Context context,
             int userId) {
         final PermissionManagerInternal permissionManagerInternal = LocalServices.getService(
@@ -149,40 +162,66 @@
             @NonNull String packageName, @UserIdInt int userId) {
         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
-        final PackageParser.Package pkg = packageManagerInternal
-                .getPackage(packageName);
-        if (pkg != null) {
-            PermissionToOpSynchronizer.syncPackage(context, pkg, userId);
+        final PackageParser.Package pkg = packageManagerInternal.getPackage(packageName);
+        if (pkg == null) {
+            return;
         }
+        final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(context);
+        synchroniser.addPackage(context, pkg, userId);
+        final String[] sharedPkgNames = packageManagerInternal.getPackagesForSharedUserId(
+                pkg.mSharedUserId, userId);
+        if (sharedPkgNames != null) {
+            for (String sharedPkgName : sharedPkgNames) {
+                final PackageParser.Package sharedPkg = packageManagerInternal
+                        .getPackage(sharedPkgName);
+                if (sharedPkg != null) {
+                    synchroniser.addPackage(context, sharedPkg, userId);
+                }
+            }
+        }
+        synchroniser.syncPackages();
     }
 
     private static void synchronizePermissionsAndAppOpsForUser(@NonNull Context context,
             @UserIdInt int userId) {
         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
-        final PermissionToOpSynchronizer synchronizer = new PermissionToOpSynchronizer(context);
+        final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(context);
         packageManagerInternal.forEachPackage((pkg) ->
                 synchronizer.addPackage(context, pkg, userId));
         synchronizer.syncPackages();
     }
 
-    private static class PermissionToOpSynchronizer {
+    /**
+     * Synchronizes permission to app ops. You *must* always sync all packages
+     * in a shared UID at the same time to ensure proper synchronization.
+     */
+    private static class PermissionToOpSynchroniser {
         private final @NonNull Context mContext;
 
+        private final @NonNull SparseIntArray mUids = new SparseIntArray();
         private final @NonNull SparseArray<String> mPackageNames = new SparseArray<>();
         private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray();
         private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray();
 
-        PermissionToOpSynchronizer(@NonNull Context context) {
+        PermissionToOpSynchroniser(@NonNull Context context) {
             mContext = context;
         }
 
-        private void addPackage(@NonNull Context context,
-                @NonNull PackageParser.Package pkg, @UserIdInt int userId) {
-            addPackage(context, pkg, userId, this::addAllowedEntry, this::addIgnoredEntry);
-        }
-
         void syncPackages() {
+            // TRICKY: we set the app op for a restricted permission to allow if the app
+            // requesting the permission is whitelisted and to deny if the app requesting
+            // the permission is not whitelisted. However, there is another case where an
+            // app in a shared user can access a component in another app in the same shared
+            // user due to being in the same shared user and not by having the permission
+            // that guards the component form the rest of the world. We need to handle this.
+            // The way we do this is by setting app ops corresponding to non requested
+            // restricted permissions to allow as this would allow the shared uid access
+            // case and be okay for other apps as they would not have the permission and
+            // would fail on the permission checks before reaching the app op check.
+            final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid =
+                    new SparseArray<>();
+
             final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
             final int allowedCount = mAllowedUidOps.size();
             for (int i = 0; i < allowedCount; i++) {
@@ -190,31 +229,84 @@
                 final int uid = mAllowedUidOps.valueAt(i);
                 final String packageName = mPackageNames.valueAt(i);
                 setUidModeAllowed(appOpsManager, opCode, uid, packageName);
+
+                // Keep track this permission was requested by the UID.
+                List<String> unrequestedRestrictedPermissions =
+                        unrequestedRestrictedPermissionsForUid.get(uid);
+                if (unrequestedRestrictedPermissions == null) {
+                    unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
+                    unrequestedRestrictedPermissionsForUid.put(uid,
+                            unrequestedRestrictedPermissions);
+                }
+                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode));
+
+                mUids.delete(uid);
             }
             final int defaultCount = mDefaultUidOps.size();
             for (int i = 0; i < defaultCount; i++) {
                 final int opCode = mDefaultUidOps.keyAt(i);
                 final int uid = mDefaultUidOps.valueAt(i);
                 setUidModeDefault(appOpsManager, opCode, uid);
+
+                // Keep track this permission was requested by the UID.
+                List<String> unrequestedRestrictedPermissions =
+                        unrequestedRestrictedPermissionsForUid.get(uid);
+                if (unrequestedRestrictedPermissions == null) {
+                    unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
+                    unrequestedRestrictedPermissionsForUid.put(uid,
+                            unrequestedRestrictedPermissions);
+                }
+                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode));
+
+                mUids.delete(uid);
+            }
+
+            // Give root access
+            mUids.put(Process.ROOT_UID, Process.ROOT_UID);
+
+            // Add records for UIDs that don't use any restricted permissions.
+            final int uidCount = mUids.size();
+            for (int i = 0; i < uidCount; i++) {
+                final int uid = mUids.keyAt(i);
+                unrequestedRestrictedPermissionsForUid.put(uid,
+                        new ArrayList<>(sAllRestrictedPermissions));
+            }
+
+            // Flip ops for all unrequested restricted permission for the UIDs.
+            final int unrequestedUidCount = unrequestedRestrictedPermissionsForUid.size();
+            for (int i = 0; i < unrequestedUidCount; i++) {
+                final List<String> unrequestedRestrictedPermissions =
+                        unrequestedRestrictedPermissionsForUid.valueAt(i);
+                if (unrequestedRestrictedPermissions != null) {
+                    final int uid = unrequestedRestrictedPermissionsForUid.keyAt(i);
+                    final String[] packageNames = (uid != Process.ROOT_UID)
+                            ? mContext.getPackageManager().getPackagesForUid(uid)
+                            : new String[] {"root"};
+                    if (packageNames == null) {
+                        continue;
+                    }
+                    final int permissionCount = unrequestedRestrictedPermissions.size();
+                    for (int j = 0; j < permissionCount; j++) {
+                        final String permission = unrequestedRestrictedPermissions.get(j);
+                        for (String packageName : packageNames) {
+                            setUidModeAllowed(appOpsManager,
+                                    AppOpsManager.permissionToOpCode(permission), uid,
+                                    packageName);
+                        }
+                    }
+                }
             }
         }
 
-        static void syncPackage(@NonNull Context context, @NonNull PackageParser.Package pkg,
-                @UserIdInt int userId) {
-            addPackage(context, pkg, userId, PermissionToOpSynchronizer::setUidModeAllowed,
-                    PermissionToOpSynchronizer::setUidModeDefault);
-        }
-
-        private static void addPackage(@NonNull Context context,
-                @NonNull PackageParser.Package pkg, @UserIdInt int userId,
-                @NonNull QuadConsumer<AppOpsManager, Integer, Integer, String> allowedConsumer,
-                @NonNull TriConsumer<AppOpsManager, Integer, Integer> defaultConsumer) {
+        private void addPackage(@NonNull Context context,
+                @NonNull PackageParser.Package pkg, @UserIdInt int userId) {
             final PackageManager packageManager = context.getPackageManager();
-            final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
 
             final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid));
             final UserHandle userHandle = UserHandle.of(userId);
 
+            mUids.put(uid, uid);
+
             final int permissionCount = pkg.requestedPermissions.size();
             for (int i = 0; i < permissionCount; i++) {
                 final String permission = pkg.requestedPermissions.get(i);
@@ -241,9 +333,10 @@
 
                 if (permissionInfo.isHardRestricted()) {
                     if (applyRestriction) {
-                        defaultConsumer.accept(appOpsManager, opCode, uid);
+                        mDefaultUidOps.put(opCode, uid);
                     } else {
-                        allowedConsumer.accept(appOpsManager, opCode, uid, pkg.packageName);
+                        mPackageNames.put(opCode, pkg.packageName);
+                        mAllowedUidOps.put(opCode, uid);
                     }
                 } else if (permissionInfo.isSoftRestricted()) {
                     //TODO: Implement soft restrictions like storage here.
@@ -251,19 +344,6 @@
             }
         }
 
-        @SuppressWarnings("unused")
-        private void addAllowedEntry(@NonNull AppOpsManager appOpsManager, int opCode,
-                int uid, @NonNull String packageName) {
-            mPackageNames.put(opCode, packageName);
-            mAllowedUidOps.put(opCode, uid);
-        }
-
-        @SuppressWarnings("unused")
-        private void addIgnoredEntry(@NonNull AppOpsManager appOpsManager,
-                int opCode, int uid) {
-            mDefaultUidOps.put(opCode, uid);
-        }
-
         private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager,
                 int opCode, int uid, @NonNull String packageName) {
             final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b3f1c55..d0ca861 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1361,9 +1361,9 @@
         if (mKeyguardDelegate.isShowing()) {
             // Double the time it takes to take a screenshot from the keyguard
             return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
-                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+                    ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
         }
-        return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
+        return ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout();
     }
 
     private long getRingerToggleChordDelay() {
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index f83b3ea..96924c04 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1458,8 +1458,18 @@
 
     private void pullNumBiometricsEnrolled(int modality, int tagId, long elapsedNanos,
             long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
-        FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
-        FaceManager faceManager = mContext.getSystemService(FaceManager.class);
+        final PackageManager pm = mContext.getPackageManager();
+        FingerprintManager fingerprintManager = null;
+        FaceManager faceManager = null;
+
+        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+            fingerprintManager = mContext.getSystemService(
+                    FingerprintManager.class);
+        }
+        if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+            faceManager = mContext.getSystemService(FaceManager.class);
+        }
+
         if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT && fingerprintManager == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d52ba16..9908b36 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2629,7 +2629,8 @@
                     0, null, new UserHandle(serviceUserId)));
             if (!mContext.bindServiceAsUser(intent, newConn,
                     Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
-                            | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                            | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+                            | Context.BIND_INCLUDE_CAPABILITIES,
                     new UserHandle(serviceUserId))) {
                 String msg = "Unable to bind service: "
                         + componentName;
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 56a6c3c..a9a6b19 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -266,6 +266,11 @@
     }
 
     @Override
+    public void ensureZygoteStarted() {
+        WebViewZygote.getProcess();
+    }
+
+    @Override
     public boolean isMultiProcessDefaultEnabled() {
         // Multiprocess is enabled for all 64-bit devices, since the ability to run the renderer
         // process in 32-bit when it's a separate process typically results in a net memory saving.
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index 3fb5279..743740d 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -61,5 +61,7 @@
     public int getMultiProcessSetting(Context context);
     public void setMultiProcessSetting(Context context, int value);
     public void notifyZygote(boolean enableMultiProcess);
+    /** Start the zygote if it's not already running. */
+    public void ensureZygoteStarted();
     public boolean isMultiProcessDefaultEnabled();
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index f704c30..890456a 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.pm.PackageInfo;
+import android.os.AsyncTask;
 import android.os.UserHandle;
 import android.webkit.WebViewProviderInfo;
 import android.webkit.WebViewProviderResponse;
@@ -81,6 +82,14 @@
         migrateFallbackStateOnBoot();
         mWebViewUpdater.prepareWebViewInSystemServer();
         mSystemInterface.notifyZygote(isMultiProcessEnabled());
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(this::startZygoteWhenReady);
+    }
+
+    void startZygoteWhenReady() {
+        // Wait on a background thread for RELRO creation to be done. We ignore the return value
+        // because even if RELRO creation failed we still want to start the zygote.
+        waitForAndGetProvider();
+        mSystemInterface.ensureZygoteStarted();
     }
 
     void handleNewUser(int userId) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 91ec4a0..ed3ec94 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -87,7 +87,10 @@
 import static android.os.Build.VERSION_CODES.HONEYCOMB;
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Process.SYSTEM_UID;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
 
 import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
@@ -195,6 +198,7 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.AppTransitionAnimationSpec;
+import android.view.DisplayCutout;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IApplicationToken;
 import android.view.RemoteAnimationDefinition;
@@ -382,6 +386,12 @@
     private int[] mHorizontalSizeConfigurations;
     private int[] mSmallestSizeConfigurations;
 
+    /**
+     * The precomputed display insets for resolving configuration. It will be non-null if
+     * {@link #shouldUseSizeCompatMode} returns {@code true}.
+     */
+    private CompatDisplayInsets mCompatDisplayInsets;
+
     boolean pendingVoiceInteractionStart;   // Waiting for activity-invoked voice session
     IVoiceInteractionSession voiceSession;  // Voice interaction session for this activity
 
@@ -693,13 +703,13 @@
         }
     }
 
-    void scheduleTopResumedActivityChanged(boolean onTop) {
+    boolean scheduleTopResumedActivityChanged(boolean onTop) {
         if (!attachedToProcess()) {
             if (DEBUG_STATES) {
                 Slog.w(TAG, "Can't report activity position update - client not running"
                                 + ", activityRecord=" + this);
             }
-            return;
+            return false;
         }
         try {
             if (DEBUG_STATES) {
@@ -710,7 +720,9 @@
                     TopResumedActivityChangeItem.obtain(onTop));
         } catch (RemoteException e) {
             // If process died, whatever.
+            return false;
         }
+        return true;
     }
 
     void updateMultiWindowMode() {
@@ -863,7 +875,7 @@
             name = intent.getComponent().flattenToShortString();
         }
 
-        private static ActivityRecord tokenToActivityRecordLocked(Token token) {
+        private static @Nullable ActivityRecord tokenToActivityRecordLocked(Token token) {
             if (token == null) {
                 return null;
             }
@@ -891,7 +903,7 @@
         }
     }
 
-    static ActivityRecord forTokenLocked(IBinder token) {
+    static @Nullable ActivityRecord forTokenLocked(IBinder token) {
         try {
             return Token.tokenToActivityRecordLocked((Token)token);
         } catch (ClassCastException e) {
@@ -1595,8 +1607,8 @@
             try {
                 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
                 ar.add(rintent);
-                mAtmService.getLifecycleManager().scheduleTransaction(
-                        app.getThread(), appToken, NewIntentItem.obtain(ar, mState == PAUSED));
+                mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
+                        NewIntentItem.obtain(ar));
                 unsent = false;
             } catch (RemoteException e) {
                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1937,14 +1949,20 @@
             return false;
         }
 
+        // Whether the activity is on the sleeping display.
+        // TODO(b/129750406): This should be applied for the default display, too.
+        final boolean isDisplaySleeping = getDisplay().isSleeping()
+                && getDisplayId() != DEFAULT_DISPLAY;
         // Whether this activity is the top activity of this stack.
         final boolean isTop = this == stack.getTopActivity();
         // Exclude the case where this is the top activity in a pinned stack.
         final boolean isTopNotPinnedStack = stack.isAttached()
                 && stack.getDisplay().isTopNotPinnedStack(stack);
-        // Now check whether it's really visible depending on Keyguard state.
-        return stack.checkKeyguardVisibility(this,
+        // Now check whether it's really visible depending on Keyguard state, and update
+        // {@link ActivityStack} internal states.
+        final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
                 visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
+        return visibleIgnoringDisplayStatus && !isDisplaySleeping;
     }
 
     boolean shouldBeVisible() {
@@ -2127,10 +2145,13 @@
     static void activityResumedLocked(IBinder token) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
-        if (r != null) {
-            r.icicle = null;
-            r.haveState = false;
+        if (r == null) {
+            // If an app reports resumed after a long delay, the record on server side might have
+            // been removed (e.g. destroy timeout), so the token could be null.
+            return;
         }
+        r.icicle = null;
+        r.haveState = false;
 
         final ActivityDisplay display = r.getDisplay();
         if (display != null) {
@@ -2828,6 +2849,11 @@
                 // The smallest screen width is the short side of screen bounds. Because the bounds
                 // and density won't be changed, smallestScreenWidthDp is also fixed.
                 overrideConfig.smallestScreenWidthDp = parentConfig.smallestScreenWidthDp;
+
+                final ActivityDisplay display = getDisplay();
+                if (display != null && display.mDisplayContent != null) {
+                    mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent);
+                }
             }
         }
         onRequestedOverrideConfigurationChanged(overrideConfig);
@@ -2844,7 +2870,7 @@
             super.resolveOverrideConfiguration(newParentConfiguration);
             if (hasOverrideBounds) {
                 task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
-                        newParentConfiguration, true /* insideParentBounds */);
+                        newParentConfiguration);
             }
         }
 
@@ -2917,9 +2943,8 @@
             resolvedBounds.right -= resolvedAppBounds.left;
         }
 
-        // In size compatibility mode, activity is allowed to have larger bounds than its parent.
         task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
-                false /* insideParentBounds */);
+                mCompatDisplayInsets);
         // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
         // the parent bounds appropriately.
         if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
@@ -3405,7 +3430,6 @@
             transaction.addCallback(callbackItem);
             transaction.setLifecycleStateRequest(lifecycleItem);
             mAtmService.getLifecycleManager().scheduleTransaction(transaction);
-            mStackSupervisor.updateTopResumedActivityIfNeeded();
             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
             // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
@@ -3446,6 +3470,7 @@
         // configuration.
         getRequestedOverrideConfiguration().setToDefaults();
         getResolvedOverrideConfiguration().setToDefaults();
+        mCompatDisplayInsets = null;
         if (visible) {
             // Configuration will be ensured when becoming visible, so if it is already visible,
             // then the manual update is needed.
@@ -3792,4 +3817,46 @@
         writeToProto(proto);
         proto.end(token);
     }
+
+    /**
+     * The precomputed insets of the display in each rotation. This is used to make the size
+     * compatibility mode activity compute the configuration without relying on its current display.
+     */
+    static class CompatDisplayInsets {
+        final int mDisplayWidth;
+        final int mDisplayHeight;
+
+        /** The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. */
+        final Rect[] mNonDecorInsets = new Rect[4];
+        /**
+         * The stableInsets for each rotation. Includes the status bar inset and the
+         * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and
+         * {@link Configuration#screenHeightDp}.
+         */
+        final Rect[] mStableInsets = new Rect[4];
+
+        CompatDisplayInsets(DisplayContent display) {
+            mDisplayWidth = display.mBaseDisplayWidth;
+            mDisplayHeight = display.mBaseDisplayHeight;
+            final DisplayPolicy policy = display.getDisplayPolicy();
+            final DisplayCutout cutout = display.getDisplayInfo().displayCutout;
+            for (int rotation = 0; rotation < 4; rotation++) {
+                mNonDecorInsets[rotation] = new Rect();
+                mStableInsets[rotation] = new Rect();
+                final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+                final int dw = rotated ? mDisplayHeight : mDisplayWidth;
+                final int dh = rotated ? mDisplayWidth : mDisplayHeight;
+                policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]);
+                mStableInsets[rotation].set(mNonDecorInsets[rotation]);
+                policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation);
+            }
+        }
+
+        void getDisplayBounds(Rect outBounds, int rotation) {
+            final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+            final int dw = rotated ? mDisplayHeight : mDisplayWidth;
+            final int dh = rotated ? mDisplayWidth : mDisplayHeight;
+            outBounds.set(0, 0, dw, dh);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6bc9fc8..419f5be 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1500,7 +1500,6 @@
                 + " callers=" + Debug.getCallers(5));
         r.setState(RESUMED, "minimalResumeActivityLocked");
         r.completeResumeLocked();
-        mStackSupervisor.updateTopResumedActivityIfNeeded();
         if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
                 "Launch completed; removing icicle of " + r.icicle);
     }
@@ -1804,7 +1803,7 @@
             if (prev.finishing) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
                 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
-                        "completedPausedLocked");
+                        "completePausedLocked");
             } else if (prev.hasProcess()) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
                         + " wasStopping=" + wasStopping + " visible=" + prev.visible);
@@ -2571,7 +2570,6 @@
             // Protect against recursion.
             mInResumeTopActivity = true;
             result = resumeTopActivityInnerLocked(prev, options);
-            mStackSupervisor.updateTopResumedActivityIfNeeded();
 
             // When resuming the top activity, it may be necessary to pause the top activity (for
             // example, returning to the lock screen. We suppress the normal pause logic in
@@ -2606,6 +2604,7 @@
         if (DEBUG_STACK) Slog.d(TAG_STACK, "setResumedActivity stack:" + this + " + from: "
                 + mResumedActivity + " to:" + r + " reason:" + reason);
         mResumedActivity = r;
+        mStackSupervisor.updateTopResumedActivityIfNeeded();
     }
 
     @GuardedBy("mService")
@@ -2962,8 +2961,7 @@
                 }
 
                 if (next.newIntents != null) {
-                    transaction.addCallback(NewIntentItem.obtain(next.newIntents,
-                            false /* andPause */));
+                    transaction.addCallback(NewIntentItem.obtain(next.newIntents));
                 }
 
                 // Well the app will no longer be stopped.
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 53dc1df..a9d76a6 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -853,7 +853,6 @@
 
                 // Schedule transaction.
                 mService.getLifecycleManager().scheduleTransaction(clientTransaction);
-                updateTopResumedActivityIfNeeded();
 
                 if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
                         && mService.mHasHeavyWeightFeature) {
@@ -2321,8 +2320,8 @@
         // mTopResumedActivityWaitingForPrev == true at this point would mean that an activity
         // before the prevTopActivity one hasn't reported back yet. So server never sent the top
         // resumed state change message to prevTopActivity.
-        if (prevActivityReceivedTopState) {
-            prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */);
+        if (prevActivityReceivedTopState
+                && prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */)) {
             scheduleTopResumedStateLossTimeout(prevTopActivity);
             mTopResumedActivityWaitingForPrev = true;
         }
@@ -2776,8 +2775,8 @@
                         true /* forceSend */, targetActivity);
                 mActivityMetricsLogger.notifyActivityLaunching(task.intent);
                 try {
-                    mService.moveTaskToFrontLocked(task.taskId, 0, options,
-                            true /* fromRecents */);
+                    mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
+                            task.taskId, 0, options, true /* fromRecents */);
                     // Apply options to prevent pendingOptions be taken by client to make sure
                     // the override pending app transition will be applied immediately.
                     targetActivity.applyOptionsLocked();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 3b358e8..473a875 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -759,8 +759,8 @@
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                         "shouldAbortBackgroundActivityStart");
-                abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid, callingPid,
-                        callingPackage, realCallingUid, realCallingPid, callerApp,
+                abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid,
+                        callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
                         originatingPendingIntent, allowBackgroundActivityStart, intent);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -768,14 +768,7 @@
             abort |= (abortBackgroundStart && !mService.isBackgroundActivityStartsEnabled());
             // TODO: remove this toast after feature development is done
             if (abortBackgroundStart) {
-                final Resources res = mService.mContext.getResources();
-                final String toastMsg = res.getString(abort
-                            ? R.string.activity_starter_block_bg_activity_starts_enforcing
-                            : R.string.activity_starter_block_bg_activity_starts_permissive,
-                        callingPackage);
-                mService.mUiHandler.post(() -> {
-                    Toast.makeText(mService.mContext, toastMsg, Toast.LENGTH_LONG).show();
-                });
+                showBackgroundActivityBlockedToast(abort, callingPackage);
             }
         }
 
@@ -935,7 +928,7 @@
         return res;
     }
 
-    private boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
+    boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
             final String callingPackage, int realCallingUid, int realCallingPid,
             WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
             boolean allowBackgroundActivityStart, Intent intent) {
@@ -1025,11 +1018,11 @@
         if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
             return false;
         }
-        // don't abort if the callingPackage is the device owner
-        if (mService.isDeviceOwner(callingPackage)) {
+        // don't abort if the callingUid is the device owner
+        if (mService.isDeviceOwner(callingUid)) {
             return false;
         }
-        // don't abort if the callingPackage has companion device
+        // don't abort if the callingUid has companion device
         final int callingUserId = UserHandle.getUserId(callingUid);
         if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
             return false;
@@ -1048,7 +1041,7 @@
                 + "; realCallingUid: " + realCallingUid
                 + "; isRealCallingUidForeground: " + isRealCallingUidForeground
                 + "; isRealCallingUidPersistentSystemProcess: "
-                        + isRealCallingUidPersistentSystemProcess
+                + isRealCallingUidPersistentSystemProcess
                 + "; originatingPendingIntent: " + originatingPendingIntent
                 + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
                 + "; intent: " + intent
@@ -1076,6 +1069,18 @@
         return false;
     }
 
+    // TODO: remove this toast after feature development is done
+    void showBackgroundActivityBlockedToast(boolean abort, String callingPackage) {
+        final Resources res = mService.mContext.getResources();
+        final String toastMsg = res.getString(abort
+                        ? R.string.activity_starter_block_bg_activity_starts_enforcing
+                        : R.string.activity_starter_block_bg_activity_starts_permissive,
+                callingPackage);
+        mService.mUiHandler.post(() -> {
+            Toast.makeText(mService.mContext, toastMsg, Toast.LENGTH_LONG).show();
+        });
+    }
+
     /**
      * Creates a launch intent for the given auxiliary resolution data.
      */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index b2e5b6a..7d25466 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -507,9 +507,9 @@
     public abstract boolean isUidForeground(int uid);
 
     /**
-     * Called by DevicePolicyManagerService to set the package name of the device owner.
+     * Called by DevicePolicyManagerService to set the uid of the device owner.
      */
-    public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg);
+    public abstract void setDeviceOwnerUid(int uid);
 
     /** Set all associated companion app that belongs to an userId. */
     public abstract void setCompanionAppPackages(int userId, Set<String> companionAppPackages);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 10ae782..b424904 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -633,7 +633,7 @@
 
     private FontScaleSettingObserver mFontScaleSettingObserver;
 
-    private String mDeviceOwnerPackageName;
+    private int mDeviceOwnerUid = Process.INVALID_UID;
 
     private final class FontScaleSettingObserver extends ContentObserver {
         private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE);
@@ -2281,25 +2281,48 @@
      * TODO: Add mController hook
      */
     @Override
-    public void moveTaskToFront(int taskId, int flags, Bundle bOptions) {
+    public void moveTaskToFront(IApplicationThread appThread, String callingPackage, int taskId,
+            int flags, Bundle bOptions) {
         mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
 
         if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
         synchronized (mGlobalLock) {
-            moveTaskToFrontLocked(taskId, flags, SafeActivityOptions.fromBundle(bOptions),
-                    false /* fromRecents */);
+            moveTaskToFrontLocked(appThread, callingPackage, taskId, flags,
+                    SafeActivityOptions.fromBundle(bOptions), false /* fromRecents */);
         }
     }
 
-    void moveTaskToFrontLocked(int taskId, int flags, SafeActivityOptions options,
+    void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
+            @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options,
             boolean fromRecents) {
 
-        if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
-                Binder.getCallingUid(), -1, -1, "Task to front")) {
+        final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
+        if (!isSameApp(callingUid, callingPackage)) {
+            String msg = "Permission Denial: moveTaskToFrontLocked() from pid="
+                    + Binder.getCallingPid() + " as package " + callingPackage;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        if (!checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, "Task to front")) {
             SafeActivityOptions.abort(options);
             return;
         }
         final long origId = Binder.clearCallingIdentity();
+        WindowProcessController callerApp = null;
+        if (appThread != null) {
+            callerApp = getProcessController(appThread);
+        }
+        final ActivityStarter starter = getActivityStartController().obtainStarter(
+                null /* intent */, "moveTaskToFront");
+        if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
+                -1, callerApp, null, false, null)) {
+            boolean abort = !isBackgroundActivityStartsEnabled();
+            starter.showBackgroundActivityBlockedToast(abort, callingPackage);
+            if (abort) {
+                return;
+            }
+        }
         try {
             final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
             if (task == null) {
@@ -2331,6 +2354,26 @@
         }
     }
 
+    /**
+     * Return true if callingUid is system, or packageName belongs to that callingUid.
+     */
+    boolean isSameApp(int callingUid, @Nullable String packageName) {
+        try {
+            if (callingUid != 0 && callingUid != SYSTEM_UID) {
+                if (packageName == null) {
+                    return false;
+                }
+                final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+                        UserHandle.getUserId(callingUid));
+                return UserHandle.isSameApp(callingUid, uid);
+            }
+        } catch (RemoteException e) {
+            // Should not happen
+        }
+        return true;
+    }
+
     boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
             int callingPid, int callingUid, String name) {
         if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -5291,7 +5334,10 @@
         return mAmInternal.isBackgroundActivityStartsEnabled();
     }
 
-    boolean isPackageNameWhitelistedForBgActivityStarts(String packageName) {
+    boolean isPackageNameWhitelistedForBgActivityStarts(@Nullable String packageName) {
+        if (packageName == null) {
+            return false;
+        }
         return mAmInternal.isPackageNameWhitelistedForBgActivityStarts(packageName);
     }
 
@@ -5830,15 +5876,12 @@
                 || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
     }
 
-    boolean isDeviceOwner(String packageName) {
-        if (packageName == null) {
-            return false;
-        }
-        return packageName.equals(mDeviceOwnerPackageName);
+    boolean isDeviceOwner(int uid) {
+        return uid >= 0 && mDeviceOwnerUid == uid;
     }
 
-    void setDeviceOwnerPackageName(String deviceOwnerPkg) {
-        mDeviceOwnerPackageName = deviceOwnerPkg;
+    void setDeviceOwnerUid(int uid) {
+        mDeviceOwnerUid = uid;
     }
 
     /**
@@ -7288,9 +7331,9 @@
         }
 
         @Override
-        public void setDeviceOwnerPackageName(String deviceOwnerPkg) {
+        public void setDeviceOwnerUid(int uid) {
             synchronized (mGlobalLock) {
-                ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg);
+                ActivityTaskManagerService.this.setDeviceOwnerUid(uid);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 441c593..e967a92f 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
+import android.util.Slog;
 
 /**
  * An implementation of IAppTask, that allows an app to manage its own tasks via
@@ -34,6 +35,7 @@
  * only the process that calls getAppTasks() can call the AppTask methods.
  */
 class AppTaskImpl extends IAppTask.Stub {
+    private static final String TAG = "AppTaskImpl";
     private ActivityTaskManagerService mService;
 
     private int mTaskId;
@@ -90,16 +92,36 @@
     }
 
     @Override
-    public void moveToFront() {
+    public void moveToFront(IApplicationThread appThread, String callingPackage) {
         checkCaller();
         // Will bring task to front if it already has a root activity.
         final int callingPid = Binder.getCallingPid();
         final int callingUid = Binder.getCallingUid();
+        if (!mService.isSameApp(callingUid, callingPackage)) {
+            String msg = "Permission Denial: moveToFront() from pid="
+                    + Binder.getCallingPid() + " as package " + callingPackage;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mService.mGlobalLock) {
-                mService.mStackSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId,
-                        null);
+                WindowProcessController callerApp = null;
+                if (appThread != null) {
+                    callerApp = mService.getProcessController(appThread);
+                }
+                final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
+                        null /* intent */, "moveToFront");
+                if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
+                        callingPackage, -1, -1, callerApp, null, false, null)) {
+                    boolean abort = !mService.isBackgroundActivityStartsEnabled();
+                    starter.showBackgroundActivityBlockedToast(abort, callingPackage);
+                    if (abort) {
+                        return;
+                    }
+                }
+                mService.mStackSupervisor.startActivityFromRecents(callingPid,
+                        callingUid, mTaskId, null);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index f9980be..c1d872f 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -73,6 +73,13 @@
     /** Schedule a PiP mode changed callback when this animation ends. */
     public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2;
 
+    public static final int BOUNDS = 0;
+    public static final int FADE_IN = 1;
+
+    @IntDef({BOUNDS, FADE_IN}) public @interface AnimationType {}
+
+    private static final int FADE_IN_DURATION = 500;
+
     // Only accessed on UI thread.
     private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
 
@@ -115,6 +122,7 @@
     private boolean mFinishAnimationAfterTransition = false;
     private final AnimationHandler mAnimationHandler;
     private Choreographer mChoreographer;
+    private @AnimationType int mAnimationType;
 
     private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
 
@@ -140,6 +148,7 @@
             implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
 
         private final BoundsAnimationTarget mTarget;
+        private final @AnimationType int mAnimationType;
         private final Rect mFrom = new Rect();
         private final Rect mTo = new Rect();
         private final Rect mTmpRect = new Rect();
@@ -166,8 +175,8 @@
 
         // Depending on whether we are animating from
         // a smaller to a larger size
-        private final int mFrozenTaskWidth;
-        private final int mFrozenTaskHeight;
+        private int mFrozenTaskWidth;
+        private int mFrozenTaskHeight;
 
         // Timeout callback to ensure we continue the animation if waiting for resuming or app
         // windows drawn fails
@@ -176,12 +185,13 @@
             resume();
         };
 
-        BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
-                @SchedulePipModeChangedState int schedulePipModeChangedState,
+        BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from,
+                Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState,
                 @SchedulePipModeChangedState int prevShedulePipModeChangedState,
                 boolean moveFromFullscreen, boolean moveToFullscreen, Rect frozenTask) {
             super();
             mTarget = target;
+            mAnimationType = animationType;
             mFrom.set(from);
             mTo.set(to);
             mSchedulePipModeChangedState = schedulePipModeChangedState;
@@ -195,12 +205,14 @@
             // to their final size immediately so we can use scaling to make the window
             // larger. Likewise if we are going from bigger to smaller, we want to wait until
             // the end so we don't have to upscale from the smaller finished size.
-            if (animatingToLargerSize()) {
-                mFrozenTaskWidth = mTo.width();
-                mFrozenTaskHeight = mTo.height();
-            } else {
-                mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width();
-                mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
+            if (mAnimationType == BOUNDS) {
+                if (animatingToLargerSize()) {
+                    mFrozenTaskWidth = mTo.width();
+                    mFrozenTaskHeight = mTo.height();
+                } else {
+                    mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width();
+                    mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
+                }
             }
         }
 
@@ -222,8 +234,9 @@
             // otherwise.
             boolean continueAnimation;
             if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) {
-                continueAnimation = mTarget.onAnimationStart(mSchedulePipModeChangedState ==
-                        SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */);
+                continueAnimation = mTarget.onAnimationStart(
+                        mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START,
+                        false /* forceUpdate */, mAnimationType);
 
                 // When starting an animation from fullscreen, pause here and wait for the
                 // windows-drawn signal before we start the rest of the transition down into PiP.
@@ -238,7 +251,8 @@
                 // However, we still need to report to them that they are leaving PiP, so this will
                 // force an update via a mode changed callback.
                 continueAnimation = mTarget.onAnimationStart(
-                        true /* schedulePipModeChangedCallback */, true /* forceUpdate */);
+                        true /* schedulePipModeChangedCallback */, true /* forceUpdate */,
+                        mAnimationType);
             } else {
                 // The animation is already running, but we should check that the TaskStack is still
                 // valid before continuing with the animation
@@ -285,6 +299,13 @@
         @Override
         public void onAnimationUpdate(ValueAnimator animation) {
             final float value = (Float) animation.getAnimatedValue();
+            if (mAnimationType == FADE_IN) {
+                if (!mTarget.setPinnedStackAlpha(value)) {
+                    cancelAndCallAnimationEnd();
+                }
+                return;
+            }
+
             final float remains = 1 - value;
             mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value + 0.5f);
             mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f);
@@ -408,16 +429,29 @@
 
     public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
             int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
-            boolean moveFromFullscreen, boolean moveToFullscreen) {
+            boolean moveFromFullscreen, boolean moveToFullscreen,
+            @AnimationType int animationType) {
         animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState,
-                moveFromFullscreen, moveToFullscreen);
+                moveFromFullscreen, moveToFullscreen, animationType);
     }
 
     @VisibleForTesting
     BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to,
             int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
-            boolean moveFromFullscreen, boolean moveToFullscreen) {
+            boolean moveFromFullscreen, boolean moveToFullscreen,
+            @AnimationType int animationType) {
         final BoundsAnimator existing = mRunningAnimations.get(target);
+        // animateBoundsImpl gets called twice for each animation. The second time we get the final
+        // to rect that respects the shelf, which is when we want to resize. Our signal for fade in
+        // comes in from how to enter into pip, but we also need to use the to and from rect to
+        // decide which animation we want to run finally.
+        boolean shouldResize = false;
+        if (isRunningFadeInAnimation(target)) {
+            shouldResize = true;
+            if (from.contains(to)) {
+                animationType = FADE_IN;
+            }
+        }
         final boolean replacing = existing != null;
         @SchedulePipModeChangedState int prevSchedulePipModeChangedState =
                 NO_PIP_MODE_CHANGED_CALLBACKS;
@@ -477,18 +511,34 @@
             // Since we are replacing, we skip both animation start and end callbacks
             existing.cancel();
         }
-        final BoundsAnimator animator = new BoundsAnimator(target, from, to,
+        if (shouldResize) {
+            target.setPinnedStackSize(to, null);
+        }
+        final BoundsAnimator animator = new BoundsAnimator(target, animationType, from, to,
                 schedulePipModeChangedState, prevSchedulePipModeChangedState,
                 moveFromFullscreen, moveToFullscreen, frozenTask);
         mRunningAnimations.put(target, animator);
         animator.setFloatValues(0f, 1f);
-        animator.setDuration((animationDuration != -1 ? animationDuration
-                : DEFAULT_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
+        animator.setDuration(animationType == FADE_IN ? FADE_IN_DURATION
+                : (animationDuration != -1 ? animationDuration : DEFAULT_TRANSITION_DURATION)
+                        * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
         animator.setInterpolator(mFastOutSlowInInterpolator);
         animator.start();
         return animator;
     }
 
+    public void setAnimationType(@AnimationType int animationType) {
+        mAnimationType = animationType;
+    }
+
+    /** return the current animation type. */
+    public @AnimationType int getAnimationType() {
+        @AnimationType int animationType = mAnimationType;
+        // Default to BOUNDS.
+        mAnimationType = BOUNDS;
+        return animationType;
+    }
+
     public Handler getHandler() {
         return mHandler;
     }
@@ -498,6 +548,11 @@
         mHandler.post(this::resume);
     }
 
+    private boolean isRunningFadeInAnimation(final BoundsAnimationTarget target) {
+        final BoundsAnimator existing = mRunningAnimations.get(target);
+        return existing != null && existing.mAnimationType == FADE_IN && existing.isStarted();
+    }
+
     private void resume() {
         for (int i = 0; i < mRunningAnimations.size(); i++) {
             final BoundsAnimator b = mRunningAnimations.valueAt(i);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
index 5cb80de..9f54e49e0 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
@@ -32,7 +32,8 @@
      * callbacks
      * @return whether to continue the animation
      */
-    boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate);
+    boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
+            @BoundsAnimationController.AnimationType int animationType);
 
     /**
      * @return Whether the animation should be paused waiting for the windows to draw before
@@ -53,6 +54,9 @@
      */
     boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds);
 
+    /** Sets the alpha of the animation target */
+    boolean setPinnedStackAlpha(float alpha);
+
     /**
      * Callback for the target to inform it that the animation has ended, so it can do some
      * necessary cleanup.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6ae7720..1934e25 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2775,6 +2775,16 @@
     }
 
     /**
+     * Calculates the stable insets if we already have the non-decor insets.
+     *
+     * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
+     * @param rotation The current display rotation.
+     */
+    void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
+        inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
+    }
+
+    /**
      * Calculates the stable insets without running a layout.
      *
      * @param displayRotation the current display rotation
@@ -2789,7 +2799,7 @@
 
         // Navigation bar and status bar.
         getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
-        outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
+        convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 432d75e..363db54 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -294,7 +294,16 @@
     /**
      * Called when occluded state changed.
      */
-    private void handleOccludedChanged() {
+    private void handleOccludedChanged(int displayId) {
+        // TODO(b/113840485): Handle app transition for individual display, and apply occluded
+        // state change to secondary displays.
+        // For now, only default display fully supports occluded change. Other displays only
+        // updates keygaurd sleep token on that display.
+        if (displayId != DEFAULT_DISPLAY) {
+            updateKeyguardSleepToken(displayId);
+            return;
+        }
+
         mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
         if (isKeyguardLocked()) {
             mWindowManager.deferSurfaceLayout();
@@ -303,7 +312,7 @@
                         .prepareAppTransition(resolveOccludeTransit(),
                                 false /* alwaysKeepCurrent */, 0 /* flags */,
                                 true /* forceOverride */);
-                updateKeyguardSleepToken();
+                updateKeyguardSleepToken(DEFAULT_DISPLAY);
                 mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
                 mWindowManager.executeAppTransition();
             } finally {
@@ -395,13 +404,16 @@
         for (int displayNdx = mRootActivityContainer.getChildCount() - 1;
              displayNdx >= 0; displayNdx--) {
             final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx);
-            final int displayId = display.mDisplayId;
-            final KeyguardDisplayState state = getDisplay(displayId);
-            if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
-                state.acquiredSleepToken();
-            } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
-                state.releaseSleepToken();
-            }
+            updateKeyguardSleepToken(display.mDisplayId);
+        }
+    }
+
+    private void updateKeyguardSleepToken(int displayId) {
+        final KeyguardDisplayState state = getDisplay(displayId);
+        if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
+            state.acquiredSleepToken();
+        } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
+            state.releaseSleepToken();
         }
     }
 
@@ -483,11 +495,8 @@
                 mOccluded |= controller.mWindowManager.isShowingDream();
             }
 
-            // TODO(b/113840485): Handle app transition for individual display, and apply occluded
-            // state change to secondary displays.
-            // For now, only default display can change occluded.
-            if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) {
-                controller.handleOccludedChanged();
+            if (lastOccluded != mOccluded) {
+                controller.handleOccludedChanged(mDisplayId);
             }
             if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
                     && mDismissingKeyguardActivity != null
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 144efb4..07d3fb9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -26,6 +26,8 @@
 import static android.view.WindowManager.TRANSIT_NONE;
 
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.BoundsAnimationController.BOUNDS;
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
@@ -201,7 +203,8 @@
         }
     }
 
-    private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
+    private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode,
+            boolean sendUserLeaveHint) {
         synchronized (mService.mGlobalLock) {
             if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
                     + mWindowManager.getRecentsAnimationController()
@@ -246,7 +249,18 @@
                     if (reorderMode == REORDER_MOVE_TO_TOP) {
                         // Bring the target stack to the front
                         mStackSupervisor.mNoAnimActivities.add(targetActivity);
-                        targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
+
+                        if (sendUserLeaveHint) {
+                            // Setting this allows the previous app to PiP.
+                            mStackSupervisor.mUserLeaving = true;
+                            targetStack.moveTaskToFrontLocked(targetActivity.getTaskRecord(),
+                                    true /* noAnimation */, null /* activityOptions */,
+                                    targetActivity.appTimeTracker,
+                                    "RecentsAnimation.onAnimationFinished()");
+                        } else {
+                            targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
+                        }
+
                         if (DEBUG) {
                             final ActivityStack topStack = getTopNonAlwaysOnTopStack();
                             if (topStack != targetStack) {
@@ -300,11 +314,11 @@
 
     @Override
     public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode,
-            boolean runSychronously) {
+            boolean runSychronously, boolean sendUserLeaveHint) {
         if (runSychronously) {
-            finishAnimation(reorderMode);
+            finishAnimation(reorderMode, sendUserLeaveHint);
         } else {
-            mService.mH.post(() -> finishAnimation(reorderMode));
+            mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint));
         }
     }
 
@@ -317,6 +331,10 @@
         }
         final RecentsAnimationController controller =
                 mWindowManager.getRecentsAnimationController();
+        final DisplayContent dc =
+                mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
+        dc.mBoundsAnimationController.setAnimationType(
+                controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
 
         // Cancel running recents animation and screenshot previous task when the next
         // transition starts in below cases:
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 3813669..d2c510f 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -27,6 +27,7 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
@@ -142,7 +143,9 @@
     };
 
     public interface RecentsAnimationCallbacks {
-        void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously);
+        /** Callback when recents animation is finished. */
+        void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously,
+                boolean sendUserLeaveHint);
     }
 
     private final IRecentsAnimationController mController =
@@ -179,7 +182,7 @@
         }
 
         @Override
-        public void finish(boolean moveHomeToTop) {
+        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
             if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
                     + " mCanceled=" + mCanceled);
             final long token = Binder.clearCallingIdentity();
@@ -195,7 +198,9 @@
                 mCallbacks.onAnimationFinished(moveHomeToTop
                         ? REORDER_MOVE_TO_TOP
                         : REORDER_MOVE_TO_ORIGINAL_POSITION,
-                        true /* runSynchronously */);
+                        true /* runSynchronously */, sendUserLeaveHint);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+                dc.mBoundsAnimationController.setAnimationType(FADE_IN);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -497,7 +502,8 @@
                 Slog.e(TAG, "Failed to cancel recents animation", e);
             }
             // Clean up and return to the previous app
-            mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+            mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                    false /* sendUserLeaveHint */);
         }
     }
 
@@ -542,7 +548,8 @@
                         if (DEBUG_RECENTS_ANIMATIONS) {
                             Slog.d(TAG, "mRecentScreenshotAnimator finish");
                         }
-                        mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+                        mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                                false /* sendUserLeaveHint */);
                     }, mService);
             mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
         }
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 2d5c97f..b90d602 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -275,7 +275,20 @@
             final int displayId = display.getDisplayId();
             final Surface surface = mService.mSurfaceFactory.make();
             surface.copyFrom(mSurfaceControl);
-            if (mService.mDisplayManagerInternal.screenshot(displayId, surface)) {
+            SurfaceControl.ScreenshotGraphicBuffer gb =
+                mService.mDisplayManagerInternal.screenshot(displayId);
+            if (gb != null) {
+                try {
+                    surface.attachAndQueueBuffer(gb.getGraphicBuffer());
+                } catch (RuntimeException e) {
+                    Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage());
+                }
+                // If the screenshot contains secure layers, we have to make sure the
+                // screenshot surface we display it in also has FLAG_SECURE so that
+                // the user can not screenshot secure layers via the screenshot surface.
+                if (gb.containsSecureLayers()) {
+                    t.setSecure(mSurfaceControl, true);
+                }
                 t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
                 t.setAlpha(mSurfaceControl, 0);
                 t.show(mSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 4a0831e..7714458 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -104,7 +104,8 @@
     private int mMinVisibleWidth;
     private int mMinVisibleHeight;
 
-    private Task mTask;
+    @VisibleForTesting
+    Task mTask;
     private boolean mResizing;
     private boolean mPreserveOrientation;
     private boolean mStartOrientationWasLandscape;
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 714c227..15060e1 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -22,6 +22,7 @@
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -1688,6 +1689,8 @@
             int colorBackground = 0;
             int statusBarColor = 0;
             int navigationBarColor = 0;
+            boolean statusBarContrastWhenTransparent = false;
+            boolean navigationBarContrastWhenTransparent = false;
             boolean topActivity = true;
             for (--activityNdx; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = mActivities.get(activityNdx);
@@ -1711,12 +1714,17 @@
                         colorBackground = r.taskDescription.getBackgroundColor();
                         statusBarColor = r.taskDescription.getStatusBarColor();
                         navigationBarColor = r.taskDescription.getNavigationBarColor();
+                        statusBarContrastWhenTransparent =
+                                r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
+                        navigationBarContrastWhenTransparent =
+                                r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
                     }
                 }
                 topActivity = false;
             }
             lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
-                    colorPrimary, colorBackground, statusBarColor, navigationBarColor);
+                    colorPrimary, colorBackground, statusBarColor, navigationBarColor,
+                    statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent);
             if (mTask != null) {
                 mTask.setTaskDescription(lastTaskDescription);
             }
@@ -2041,15 +2049,12 @@
         }
         mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
 
-        policy.getStableInsetsLw(displayInfo.rotation,
-                displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.displayCutout,
-                mTmpInsets);
-        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
-
-        policy.getNonDecorInsetsLw(displayInfo.rotation,
-                displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.displayCutout,
-                mTmpInsets);
+        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
+                displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
         intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
+
+        policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
+        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
     }
 
     /**
@@ -2066,7 +2071,7 @@
 
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig) {
-        computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */);
+        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
     }
 
     /**
@@ -2078,7 +2083,8 @@
      * just be inherited from the parent configuration.
      **/
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig, boolean insideParentBounds) {
+            @NonNull Configuration parentConfig,
+            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
             windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2096,6 +2102,9 @@
             inOutConfig.windowConfiguration.setAppBounds(bounds);
             outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
         }
+        // Non-null compatibility insets means the activity prefers to keep its original size, so
+        // the out bounds doesn't need to be restricted by the parent.
+        final boolean insideParentBounds = compatInsets == null;
         if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
             final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
             if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
@@ -2118,6 +2127,17 @@
                 // Set to app bounds because it excludes decor insets.
                 mTmpNonDecorBounds.set(outAppBounds);
                 mTmpStableBounds.set(outAppBounds);
+
+                // Apply the given non-decor and stable insets to calculate the corresponding bounds
+                // for screen size of configuration.
+                final int rotation = parentConfig.windowConfiguration.getRotation();
+                if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
+                    compatInsets.getDisplayBounds(mTmpBounds, rotation);
+                    intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
+                            compatInsets.mNonDecorInsets[rotation]);
+                    intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
+                            compatInsets.mStableInsets[rotation]);
+                }
             }
 
             if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 6fe8b43..f31416c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -362,11 +362,9 @@
         }
         final int color = ColorUtils.setAlphaComponent(
                 task.getTaskDescription().getBackgroundColor(), 255);
-        final int statusBarColor = task.getTaskDescription().getStatusBarColor();
-        final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
         final LayoutParams attrs = mainWindow.getAttrs();
         final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
-                attrs.privateFlags, attrs.systemUiVisibility, statusBarColor, navigationBarColor);
+                attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription());
         final int width = mainWindow.getFrameLw().width();
         final int height = mainWindow.getFrameLw().height();
 
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 3c9a46b..0b63f48 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -26,7 +26,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
-import android.hardware.HardwareBuffer;
 import android.os.Process;
 import android.os.SystemClock;
 import android.util.ArraySet;
@@ -363,8 +362,7 @@
             // TODO(b/116112787) TaskSnapshot needs bookkeep the ColorSpace of the
             // hardware bitmap when created.
             final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
-                    HardwareBuffer.createFromGraphicBuffer(mSnapshot.getSnapshot()),
-                    mSnapshot.getColorSpace());
+                    mSnapshot.getSnapshot(), mSnapshot.getColorSpace());
             if (bitmap == null) {
                 Slog.e(TAG, "Invalid task snapshot hw bitmap");
                 return false;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 39b5662..5d99db5 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -18,6 +18,8 @@
 
 import static android.graphics.Color.WHITE;
 import static android.graphics.Color.alpha;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
@@ -148,9 +150,8 @@
         final Rect tmpStableInsets = new Rect();
         final InsetsState mTmpInsetsState = new InsetsState();
         final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
-        int backgroundColor = WHITE;
-        int statusBarColor = 0;
-        int navigationBarColor = 0;
+        final TaskDescription taskDescription = new TaskDescription();
+        taskDescription.setBackgroundColor(WHITE);
         final int sysUiVis;
         final int windowFlags;
         final int windowPrivateFlags;
@@ -194,11 +195,9 @@
             layoutParams.systemUiVisibility = sysUiVis;
             layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
 
-            final TaskDescription taskDescription = task.getTaskDescription();
-            if (taskDescription != null) {
-                backgroundColor = taskDescription.getBackgroundColor();
-                statusBarColor = taskDescription.getStatusBarColor();
-                navigationBarColor = taskDescription.getNavigationBarColor();
+            final TaskDescription td = task.getTaskDescription();
+            if (td != null) {
+                taskDescription.copyFrom(td);
             }
             taskBounds = new Rect();
             task.getBounds(taskBounds);
@@ -216,8 +215,8 @@
             // Local call.
         }
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
-                surfaceControl, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
-                navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
+                surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
+                windowFlags, windowPrivateFlags, taskBounds,
                 currentOrientation);
         window.setOuter(snapshotSurface);
         try {
@@ -234,9 +233,9 @@
 
     @VisibleForTesting
     TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
-            TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
-            int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
-            Rect taskBounds, int currentOrientation) {
+            TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
+            int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds,
+            int currentOrientation) {
         mService = service;
         mSurface = new Surface();
         mHandler = new Handler(mService.mH.getLooper());
@@ -245,11 +244,12 @@
         mSurfaceControl = surfaceControl;
         mSnapshot = snapshot;
         mTitle = title;
+        int backgroundColor = taskDescription.getBackgroundColor();
         mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
         mTaskBounds = taskBounds;
         mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
-                windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
-        mStatusBarColor = statusBarColor;
+                windowPrivateFlags, sysUiVis, taskDescription);
+        mStatusBarColor = taskDescription.getStatusBarColor();
         mOrientationOnCreation = currentOrientation;
     }
 
@@ -490,7 +490,7 @@
         private final int mSysUiVis;
 
         SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
-                int statusBarColor, int navigationBarColor) {
+                TaskDescription taskDescription) {
             mWindowFlags = windowFlags;
             mWindowPrivateFlags = windowPrivateFlags;
             mSysUiVis = sysUiVis;
@@ -498,11 +498,17 @@
             final int semiTransparent = context.getColor(
                     R.color.system_bar_background_semi_transparent);
             mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
-                    semiTransparent, statusBarColor);
+                    semiTransparent, taskDescription.getStatusBarColor(), sysUiVis,
+                    SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
             mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
-                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent, navigationBarColor);
+                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
+                    taskDescription.getNavigationBarColor(), sysUiVis,
+                    SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
+                            && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
             mStatusBarPaint.setColor(mStatusBarColor);
-            mNavigationBarPaint.setColor(navigationBarColor);
+            mNavigationBarPaint.setColor(mNavigationBarColor);
         }
 
         void setInsets(Rect contentInsets, Rect stableInsets) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 09baf8c..bdb4d04 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -34,6 +34,7 @@
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -148,6 +149,7 @@
     private boolean mCancelCurrentBoundsAnimation = false;
     private Rect mBoundsAnimationTarget = new Rect();
     private Rect mBoundsAnimationSourceHintBounds = new Rect();
+    private @BoundsAnimationController.AnimationType int mAnimationType;
 
     Rect mPreAnimationBounds = new Rect();
 
@@ -1572,7 +1574,8 @@
     }
 
     @Override  // AnimatesBounds
-    public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
+    public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
+            @BoundsAnimationController.AnimationType int animationType) {
         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
         synchronized (mWmService.mGlobalLock) {
             if (!isAttached()) {
@@ -1583,6 +1586,7 @@
             mBoundsAnimatingRequested = false;
             mBoundsAnimating = true;
             mCancelCurrentBoundsAnimation = false;
+            mAnimationType = animationType;
 
             // If we are changing UI mode, as in the PiP to fullscreen
             // transition, then we need to wait for the window to draw.
@@ -1599,7 +1603,8 @@
                 // I don't believe you...
             }
 
-            if (schedulePipModeChangedCallback && mActivityStack != null) {
+            if ((schedulePipModeChangedCallback || animationType == FADE_IN)
+                    && mActivityStack != null) {
                 // We need to schedule the PiP mode change before the animation up. It is possible
                 // in this case for the animation down to not have been completed, so always
                 // force-schedule and update to the client to ensure that it is notified that it
@@ -1614,6 +1619,21 @@
     @Override  // AnimatesBounds
     public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
             boolean moveToFullscreen) {
+        if (mAnimationType == BoundsAnimationController.FADE_IN) {
+            setPinnedStackAlpha(1f);
+            try {
+                mWmService.mActivityTaskManager.notifyPinnedStackAnimationEnded();
+            } catch (RemoteException e) {
+                // I don't believe you...
+            }
+            return;
+        }
+
+        onBoundAnimationEnd(schedulePipModeChangedCallback, finalStackSize, moveToFullscreen);
+    }
+
+    private void onBoundAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
+            boolean moveToFullscreen) {
         if (inPinnedWindowingMode()) {
             // Update to the final bounds if requested. This is done here instead of in the bounds
             // animator to allow us to coordinate this after we notify the PiP mode changed
@@ -1725,10 +1745,23 @@
         final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
                 schedulePipModeChangedState;
         final DisplayContent displayContent = getDisplayContent();
+        @BoundsAnimationController.AnimationType int intendedAnimationType =
+                displayContent.mBoundsAnimationController.getAnimationType();
+        if (intendedAnimationType == FADE_IN) {
+            if (fromFullscreen) {
+                setPinnedStackAlpha(0f);
+            }
+            if (toBounds.width() == fromBounds.width()
+                    && toBounds.height() == fromBounds.height()) {
+                intendedAnimationType = BoundsAnimationController.BOUNDS;
+            }
+        }
+
+        final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType;
         displayContent.mBoundsAnimationController.getHandler().post(() -> {
             displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
                     finalToBounds, animationDuration, finalSchedulePipModeChangedState,
-                    fromFullscreen, toFullscreen);
+                    fromFullscreen, toFullscreen, animationType);
         });
     }
 
@@ -1905,6 +1938,20 @@
         }
     }
 
+    @Override
+    public boolean setPinnedStackAlpha(float alpha) {
+        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
+        synchronized (mWmService.mGlobalLock) {
+            if (mCancelCurrentBoundsAnimation) {
+                return false;
+            }
+            getPendingTransaction().setAlpha(getSurfaceControl(), alpha);
+            scheduleAnimation();
+        }
+
+        return true;
+    }
+
     public DisplayInfo getDisplayInfo() {
         return mDisplayContent.getDisplayInfo();
     }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 166a33d..da873b8 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -35,7 +35,6 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
@@ -744,8 +743,7 @@
             return null;
         }
         return Bitmap.wrapHardwareBuffer(
-                HardwareBuffer.createFromGraphicBuffer(wallpaperBuffer.getGraphicBuffer()),
-                wallpaperBuffer.getColorSpace());
+                wallpaperBuffer.getGraphicBuffer(), wallpaperBuffer.getColorSpace());
     }
 
     private WindowState getTopVisibleWallpaper() {
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 57311e1..d8ebd84 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -98,14 +98,25 @@
         tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
         t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
         t.setAlpha(leash, tmp.transformation.getAlpha());
-        if (mStackClipMode == STACK_CLIP_NONE || mStackClipMode == STACK_CLIP_AFTER_ANIM) {
-            t.setWindowCrop(leash, tmp.transformation.getClipRect());
+
+        boolean cropSet = false;
+        if (mStackClipMode == STACK_CLIP_NONE) {
+            if (tmp.transformation.hasClipRect()) {
+                t.setWindowCrop(leash, tmp.transformation.getClipRect());
+                cropSet = true;
+            }
         } else {
             mTmpRect.set(mStackBounds);
-            mTmpRect.intersect(tmp.transformation.getClipRect());
+            if (tmp.transformation.hasClipRect()) {
+                mTmpRect.intersect(tmp.transformation.getClipRect());
+            }
             t.setWindowCrop(leash, mTmpRect);
+            cropSet = true;
         }
-        if (mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
+
+        // We can only apply rounded corner if a crop is set, as otherwise the value is meaningless,
+        // since it doesn't have anything it's relative to.
+        if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
             t.setCornerRadius(leash, mWindowCornerRadius);
         }
     }
diff --git a/services/core/xsd/vts/Android.bp b/services/core/xsd/vts/Android.bp
new file mode 100644
index 0000000..967750d
--- /dev/null
+++ b/services/core/xsd/vts/Android.bp
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "vts_defaultPermissions_validate_test",
+    srcs: [
+        "ValidateDefaultPermissions.cpp"
+    ],
+    static_libs: [
+        "android.hardware.audio.common.test.utility",
+        "libxml2",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/services/core/xsd/vts/Android.mk b/services/core/xsd/vts/Android.mk
new file mode 100644
index 0000000..6dc2c43
--- /dev/null
+++ b/services/core/xsd/vts/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsValidateDefaultPermissions
+include test/vts/tools/build/Android.host_config.mk
diff --git a/services/core/xsd/vts/AndroidTest.xml b/services/core/xsd/vts/AndroidTest.xml
new file mode 100644
index 0000000..4f3b2ef
--- /dev/null
+++ b/services/core/xsd/vts/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS VtsValidateDefaultPermissions.">
+    <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HostDrivenTest.push"/>
+        <option name="push" value="DATA/etc/default-permissions.xsd->/data/local/tmp/default-permissions.xsd"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="VtsValidateDefaultPermissions"/>
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" />
+        <option name="binary-test-type" value="gtest"/>
+        <option name="test-timeout" value="30s"/>
+    </test>
+</configuration>
diff --git a/services/core/xsd/vts/ValidateDefaultPermissions.cpp b/services/core/xsd/vts/ValidateDefaultPermissions.cpp
new file mode 100644
index 0000000..54c115b
--- /dev/null
+++ b/services/core/xsd/vts/ValidateDefaultPermissions.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include "utility/ValidateXml.h"
+
+TEST(CheckConfig, mediaDefaultPermissions) {
+    RecordProperty("description",
+                   "Verify that the default-permissions file "
+                   "is valid according to the schema");
+
+    const char* location = "/vendor/etc/default-permissions";
+
+    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("default-permissions.xml", {location},
+                                            "/data/local/tmp/default-permissions.xsd");
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8f2a2d2..8f1709e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4096,6 +4096,9 @@
 
     @Override
     public boolean isSeparateProfileChallengeAllowed(int userHandle) {
+        if (!isCallerWithSystemUid()) {
+            throw new SecurityException("Caller must be system");
+        }
         ComponentName profileOwner = getProfileOwner(userHandle);
         // Profile challenge is supported on N or newer release.
         return profileOwner != null &&
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 27cd70c..215e46f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -26,6 +26,7 @@
 import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
@@ -209,8 +210,11 @@
     }
 
     private void pushToActivityTaskManagerLocked() {
-        mActivityTaskManagerInternal.setDeviceOwnerPackageName(mDeviceOwner != null
-                ? mDeviceOwner.packageName : null);
+        final int uid = mDeviceOwner != null ? mPackageManagerInternal.getPackageUid(
+                mDeviceOwner.packageName,
+                PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES, mDeviceOwnerUserId)
+                : Process.INVALID_UID;
+        mActivityTaskManagerInternal.setDeviceOwnerUid(uid);
     }
 
     String getDeviceOwnerPackageName() {
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 7befd087..6b5842f 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -32,6 +32,7 @@
 import android.net.ip.IIpClientCallbacks;
 import android.net.util.SharedLog;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
@@ -148,14 +149,18 @@
     private class NetworkStackConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            log("Network stack service connected");
+            logi("Network stack service connected");
             registerNetworkStackService(service);
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            // TODO: crash/reboot the system ?
-            logWtf("Lost network stack connector", null);
+            // The system has lost its network stack (probably due to a crash in the
+            // network stack process): better crash rather than stay in a bad state where all
+            // networking is broken.
+            // onServiceDisconnected is not being called on device shutdown, so this method being
+            // called always indicates a bad state for the system server.
+            maybeCrashWithTerribleFailure("Lost network stack");
         }
     };
 
@@ -211,8 +216,7 @@
         }
 
         if (intent == null) {
-            logWtf("Could not resolve the network stack", null);
-            // TODO: crash/reboot system server ?
+            maybeCrashWithTerribleFailure("Could not resolve the network stack");
             return;
         }
 
@@ -220,9 +224,9 @@
         // NetworkStackConnection.onServiceConnected().
         if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
                 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
-            logWtf("Could not bind to network stack with " + intent, null);
+            maybeCrashWithTerribleFailure(
+                    "Could not bind to network stack in-process, or in app with " + intent);
             return;
-            // TODO: crash/reboot system server if no network stack after a timeout ?
         }
 
         log("Network stack service start requested");
@@ -270,6 +274,16 @@
         }
     }
 
+    private void maybeCrashWithTerribleFailure(@NonNull String message) {
+        logWtf(message, null);
+        if (Build.IS_DEBUGGABLE) {
+            throw new IllegalStateException(message);
+        }
+    }
+
+    /**
+     * Log a message in the local log.
+     */
     private void log(@NonNull String message) {
         synchronized (mLog) {
             mLog.log(message);
@@ -290,6 +304,15 @@
     }
 
     /**
+     * Log a message in the local and system logs.
+     */
+    private void logi(@NonNull String message) {
+        synchronized (mLog) {
+            mLog.i(message);
+        }
+    }
+
+    /**
      * For non-system server clients, get the connector registered by the system server.
      */
     private INetworkStackConnector getRemoteConnector() {
diff --git a/services/net/java/android/net/ip/IIpClient.aidl b/services/net/java/android/net/ip/IIpClient.aidl
index b834e45..1e77264 100644
--- a/services/net/java/android/net/ip/IIpClient.aidl
+++ b/services/net/java/android/net/ip/IIpClient.aidl
@@ -32,4 +32,5 @@
     void setMulticastFilter(boolean enabled);
     void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt);
     void removeKeepalivePacketFilter(int slot);
+    void setL2KeyAndGroupHint(in String l2Key, in String groupHint);
 }
diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java
index a17cb464..bb4a603 100644
--- a/services/net/java/android/net/shared/NetworkMonitorUtils.java
+++ b/services/net/java/android/net/shared/NetworkMonitorUtils.java
@@ -21,9 +21,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
 
-import android.content.Context;
 import android.net.NetworkCapabilities;
-import android.provider.Settings;
 
 /** @hide */
 public class NetworkMonitorUtils {
@@ -45,16 +43,6 @@
             "android.permission.ACCESS_NETWORK_CONDITIONS";
 
     /**
-     * Get the captive portal server HTTP URL that is configured on the device.
-     */
-    public static String getCaptivePortalServerHttpUrl(Context context, String defaultUrl) {
-        final String settingUrl = Settings.Global.getString(
-                context.getContentResolver(),
-                Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
-        return settingUrl != null ? settingUrl : defaultUrl;
-    }
-
-    /**
      * Return whether validation is required for a network.
      * @param dfltNetCap Default requested network capabilities.
      * @param nc Network capabilities of the network to test.
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 7a68e92..c0a11b2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -78,6 +78,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.annotations.GuardedBy;
@@ -403,6 +404,7 @@
         assertEquals(expectedTriggerTime, mTestTimer.getElapsed());
     }
 
+    @FlakyTest(bugId = 130313408)
     @Test
     public void testEarliestAlarmSet() {
         final PendingIntent pi6 = getNewMockPendingIntent();
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index fce7599..01f2f6b 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -68,6 +68,7 @@
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.HARDWARE_TEST"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
new file mode 100644
index 0000000..fc74c97
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.display.color;
+
+import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR;
+import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.display.ColorDisplayManager;
+import android.os.SystemProperties;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DisplayTransformManagerTest {
+
+    private DisplayTransformManager mDtm;
+    private float[] mNightDisplayMatrix;
+
+    @Before
+    public void setUp() {
+        mDtm = new DisplayTransformManager();
+        mNightDisplayMatrix = mDtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
+
+        SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, null);
+        SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, null);
+    }
+
+    @Test
+    public void setColorMode_natural() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("0" /* managed */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* natural */);
+    }
+
+    @Test
+    public void setColorMode_boosted() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("0" /* managed */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.1" /* boosted */);
+    }
+
+    @Test
+    public void setColorMode_saturated() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("1" /* unmanaged */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* natural */);
+    }
+
+    @Test
+    public void setColorMode_automatic() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("2" /* enhanced */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* natural */);
+    }
+
+    @Test
+    public void setColorMode_vendor() {
+        mDtm.setColorMode(0x100, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo(Integer.toString(0x100) /* pass-through */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* default */);
+    }
+
+    @Test
+    public void setColorMode_outOfBounds() {
+        mDtm.setColorMode(0x50, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("" /* default */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("" /* default */);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
new file mode 100644
index 0000000..3f9a57e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -0,0 +1,504 @@
+/*
+ * 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.om;
+
+import static android.content.om.OverlayInfo.STATE_DISABLED;
+import static android.content.om.OverlayInfo.STATE_ENABLED;
+import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
+import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.util.ArraySet;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class OverlayManagerServiceImplTests {
+    private OverlayManagerServiceImpl mImpl;
+    private DummyDeviceState mState;
+    private DummyListener mListener;
+
+    private static final String OVERLAY = "com.dummy.overlay";
+    private static final String TARGET = "com.dummy.target";
+    private static final int USER = 0;
+
+    private static final String OVERLAY2 = OVERLAY + "2";
+    private static final String TARGET2 = TARGET + "2";
+    private static final int USER2 = USER + 1;
+
+    private static final String OVERLAY3 = OVERLAY + "3";
+    private static final int USER3 = USER2 + 1;
+
+
+    @Before
+    public void setUp() throws Exception {
+        mState = new DummyDeviceState();
+        mListener = new DummyListener();
+        DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState);
+        mImpl = new OverlayManagerServiceImpl(pmh,
+                new DummyIdmapManager(mState, pmh),
+                new OverlayManagerSettings(),
+                new String[0],
+                mListener);
+    }
+
+    // tests: basics
+
+    @Test
+    public void testGetOverlayInfo() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        final OverlayInfo oi = mImpl.getOverlayInfo(OVERLAY, USER);
+        assertNotNull(oi);
+        assertEquals(oi.packageName, OVERLAY);
+        assertEquals(oi.targetPackageName, TARGET);
+        assertEquals(oi.userId, USER);
+    }
+
+    @Test
+    public void testGetOverlayInfosForTarget() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        installOverlayPackage(OVERLAY2, TARGET, USER, false);
+
+        installOverlayPackage(OVERLAY3, TARGET, USER2, false);
+
+        final List<OverlayInfo> ois = mImpl.getOverlayInfosForTarget(TARGET, USER);
+        assertEquals(ois.size(), 2);
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
+
+        final List<OverlayInfo> ois2 = mImpl.getOverlayInfosForTarget(TARGET, USER2);
+        assertEquals(ois2.size(), 1);
+        assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER2)));
+
+        final List<OverlayInfo> ois3 = mImpl.getOverlayInfosForTarget(TARGET, USER3);
+        assertNotNull(ois3);
+        assertEquals(ois3.size(), 0);
+
+        final List<OverlayInfo> ois4 = mImpl.getOverlayInfosForTarget("no.such.overlay", USER);
+        assertNotNull(ois4);
+        assertEquals(ois4.size(), 0);
+    }
+
+    @Test
+    public void testGetOverlayInfosForUser() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        installOverlayPackage(OVERLAY2, TARGET, USER, false);
+        installOverlayPackage(OVERLAY3, TARGET2, USER, false);
+
+        final Map<String, List<OverlayInfo>> everything = mImpl.getOverlaysForUser(USER);
+        assertEquals(everything.size(), 2);
+
+        final List<OverlayInfo> ois = everything.get(TARGET);
+        assertNotNull(ois);
+        assertEquals(ois.size(), 2);
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
+
+        final List<OverlayInfo> ois2 = everything.get(TARGET2);
+        assertNotNull(ois2);
+        assertEquals(ois2.size(), 1);
+        assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER)));
+
+        final Map<String, List<OverlayInfo>> everything2 = mImpl.getOverlaysForUser(USER2);
+        assertNotNull(everything2);
+        assertEquals(everything2.size(), 0);
+    }
+
+    @Test
+    public void testPriority() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        installOverlayPackage(OVERLAY2, TARGET, USER, false);
+        installOverlayPackage(OVERLAY3, TARGET, USER, false);
+
+        final OverlayInfo o1 = mImpl.getOverlayInfo(OVERLAY, USER);
+        final OverlayInfo o2 = mImpl.getOverlayInfo(OVERLAY2, USER);
+        final OverlayInfo o3 = mImpl.getOverlayInfo(OVERLAY3, USER);
+
+        assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+
+        assertTrue(mImpl.setLowestPriority(OVERLAY3, USER));
+        assertOverlayInfoList(TARGET, USER, o3, o1, o2);
+
+        assertTrue(mImpl.setHighestPriority(OVERLAY3, USER));
+        assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+
+        assertTrue(mImpl.setPriority(OVERLAY, OVERLAY2, USER));
+        assertOverlayInfoList(TARGET, USER, o2, o1, o3);
+    }
+
+    @Test
+    public void testOverlayInfoStateTransitions() throws Exception {
+        assertNull(mImpl.getOverlayInfo(OVERLAY, USER));
+
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+        assertState(STATE_MISSING_TARGET, OVERLAY, USER);
+
+        installTargetPackage(TARGET, USER);
+        assertState(STATE_DISABLED, OVERLAY, USER);
+
+        mImpl.setEnabled(OVERLAY, true, USER);
+        assertState(STATE_ENABLED, OVERLAY, USER);
+
+        beginUpgradeTargetPackage(TARGET, USER);
+        assertState(STATE_TARGET_IS_BEING_REPLACED, OVERLAY, USER);
+
+        endUpgradeTargetPackage(TARGET, USER);
+        assertState(STATE_ENABLED, OVERLAY, USER);
+
+        uninstallTargetPackage(TARGET, USER);
+        assertState(STATE_MISSING_TARGET, OVERLAY, USER);
+
+        installTargetPackage(TARGET, USER);
+        assertState(STATE_ENABLED, OVERLAY, USER);
+    }
+
+    @Test
+    public void testUpdateOverlaysForUser() throws Exception {
+        installTargetPackage(TARGET, USER);
+        installTargetPackage("some.other.target", USER);
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+
+        // do nothing, expect no change
+        List<String> a = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, a.size());
+        assertTrue(a.contains(TARGET));
+
+        // upgrade overlay, keep target
+        upgradeOverlayPackage(OVERLAY, TARGET, USER, true);
+        List<String> b = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, b.size());
+        assertTrue(b.contains(TARGET));
+
+        // do nothing, expect no change
+        List<String> c = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, c.size());
+        assertTrue(c.contains(TARGET));
+
+        // upgrade overlay, switch to new target
+        upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
+        List<String> d = mImpl.updateOverlaysForUser(USER);
+        assertEquals(2, d.size());
+        assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
+
+        // do nothing, expect no change
+        List<String> e = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, e.size());
+        assertTrue(e.contains("some.other.target"));
+    }
+
+    @Test
+    public void testOnOverlayPackageUpgraded() throws Exception {
+        installTargetPackage(TARGET, USER);
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+        mImpl.onOverlayPackageReplacing(OVERLAY, USER);
+        mListener.count = 0;
+        mImpl.onOverlayPackageReplaced(OVERLAY, USER);
+        assertEquals(1, mListener.count);
+
+        // upgrade to a version where the overlay has changed its target
+        upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
+        mImpl.onOverlayPackageReplacing(OVERLAY, USER);
+        mListener.count = 0;
+        mImpl.onOverlayPackageReplaced(OVERLAY, USER);
+        // expect once for the old target package, once for the new target package
+        assertEquals(2, mListener.count);
+
+        upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
+        mImpl.onOverlayPackageReplacing(OVERLAY, USER);
+        mListener.count = 0;
+        mImpl.onOverlayPackageReplaced(OVERLAY, USER);
+        assertEquals(1, mListener.count);
+    }
+
+    // tests: listener interface
+
+    @Test
+    public void testListener() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+        assertEquals(1, mListener.count);
+        mListener.count = 0;
+
+        installTargetPackage(TARGET, USER);
+        assertEquals(1, mListener.count);
+        mListener.count = 0;
+
+        mImpl.setEnabled(OVERLAY, true, USER);
+        assertEquals(1, mListener.count);
+        mListener.count = 0;
+
+        mImpl.setEnabled(OVERLAY, true, USER);
+        assertEquals(0, mListener.count);
+    }
+
+    // helper methods
+
+    private void assertState(int expected, final String overlayPackageName, int userId) {
+        int actual = mImpl.getOverlayInfo(OVERLAY, USER).state;
+        String msg = String.format("expected %s but was %s:",
+                OverlayInfo.stateToString(expected), OverlayInfo.stateToString(actual));
+        assertEquals(msg, expected, actual);
+    }
+
+    private void assertOverlayInfoList(final String targetPackageName, int userId,
+            OverlayInfo... overlayInfos) {
+        final List<OverlayInfo> expected =
+                mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+        final List<OverlayInfo> actual = Arrays.asList(overlayInfos);
+        assertEquals(expected, actual);
+    }
+
+    private void installTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) != null) {
+            throw new IllegalStateException("package already installed");
+        }
+        mState.add(packageName, null, userId, false);
+        mImpl.onTargetPackageAdded(packageName, userId);
+    }
+
+    private void beginUpgradeTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) == null) {
+            throw new IllegalStateException("package not installed");
+        }
+        mState.add(packageName, null, userId, false);
+        mImpl.onTargetPackageReplacing(packageName, userId);
+    }
+
+    private void endUpgradeTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) == null) {
+            throw new IllegalStateException("package not installed");
+        }
+        mState.add(packageName, null, userId, false);
+        mImpl.onTargetPackageReplaced(packageName, userId);
+    }
+
+    private void uninstallTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) == null) {
+            throw new IllegalStateException("package not installed");
+        }
+        mState.remove(packageName, userId);
+        mImpl.onTargetPackageRemoved(packageName, userId);
+    }
+
+    private void installOverlayPackage(String packageName, String targetPackageName, int userId,
+            boolean canCreateIdmap) {
+        if (mState.select(packageName, userId) != null) {
+            throw new IllegalStateException("package already installed");
+        }
+        mState.add(packageName, targetPackageName, userId, canCreateIdmap);
+        mImpl.onOverlayPackageAdded(packageName, userId);
+    }
+
+    private void upgradeOverlayPackage(String packageName, String targetPackageName, int userId,
+            boolean canCreateIdmap) {
+        DummyDeviceState.Package pkg = mState.select(packageName, userId);
+        if (pkg == null) {
+            throw new IllegalStateException("package not installed, cannot upgrade");
+        }
+        pkg.targetPackageName = targetPackageName;
+        pkg.canCreateIdmap = canCreateIdmap;
+    }
+
+    private void uninstallOverlayPackage(String packageName, int userId) {
+        // implement this when adding support for downloadable overlays
+        throw new IllegalArgumentException("not implemented");
+    }
+
+    private static final class DummyDeviceState {
+        private List<Package> mPackages = new ArrayList<>();
+
+        public void add(String packageName, String targetPackageName, int userId,
+                boolean canCreateIdmap) {
+            remove(packageName, userId);
+            Package pkg = new Package();
+            pkg.packageName = packageName;
+            pkg.targetPackageName = targetPackageName;
+            pkg.userId = userId;
+            pkg.canCreateIdmap = canCreateIdmap;
+            mPackages.add(pkg);
+        }
+
+        public void remove(String packageName, int userId) {
+            final Iterator<Package> iter = mPackages.iterator();
+            while (iter.hasNext()) {
+                final Package pkg = iter.next();
+                if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
+                    iter.remove();
+                    return;
+                }
+            }
+        }
+
+        public List<Package> select(int userId) {
+            List<Package> out = new ArrayList<>();
+            final int packageCount = mPackages.size();
+            for (int i = 0; i < packageCount; i++) {
+                final Package pkg = mPackages.get(i);
+                if (pkg.userId == userId) {
+                    out.add(pkg);
+                }
+            }
+            return out;
+        }
+
+        public Package select(String packageName, int userId) {
+            final int packageCount = mPackages.size();
+            for (int i = 0; i < packageCount; i++) {
+                final Package pkg = mPackages.get(i);
+                if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
+                    return pkg;
+                }
+            }
+            return null;
+        }
+
+        private static final class Package {
+            public String packageName;
+            public int userId;
+            public String targetPackageName;
+            public boolean canCreateIdmap;
+        }
+    }
+
+    private static final class DummyPackageManagerHelper implements
+            OverlayManagerServiceImpl.PackageManagerHelper {
+        private final DummyDeviceState mState;
+
+        DummyPackageManagerHelper(DummyDeviceState state) {
+            mState = state;
+        }
+
+        @Override
+        public PackageInfo getPackageInfo(@NonNull String packageName, int userId) {
+            final DummyDeviceState.Package pkg = mState.select(packageName, userId);
+            if (pkg == null) {
+                return null;
+            }
+            ApplicationInfo ai = new ApplicationInfo();
+            ai.sourceDir = String.format("%s/%s/base.apk",
+                    pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/",
+                    pkg.packageName);
+            PackageInfo pi = new PackageInfo();
+            pi.applicationInfo = ai;
+            pi.packageName = pkg.packageName;
+            pi.overlayTarget = pkg.targetPackageName;
+            pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
+            return pi;
+        }
+
+        @Override
+        public boolean signaturesMatching(@NonNull String packageName1,
+                @NonNull String packageName2, int userId) {
+            return false;
+        }
+
+        @Override
+        public List<PackageInfo> getOverlayPackages(int userId) {
+            List<PackageInfo> out = new ArrayList<>();
+            final List<DummyDeviceState.Package> packages = mState.select(userId);
+            final int packageCount = packages.size();
+            for (int i = 0; i < packageCount; i++) {
+                final DummyDeviceState.Package pkg = packages.get(i);
+                if (pkg.targetPackageName != null) {
+                    out.add(getPackageInfo(pkg.packageName, pkg.userId));
+                }
+            }
+            return out;
+        }
+    }
+
+    private static class DummyIdmapManager extends IdmapManager {
+        private final DummyDeviceState mState;
+        private Set<String> mIdmapFiles = new ArraySet<>();
+
+        DummyIdmapManager(DummyDeviceState state, DummyPackageManagerHelper packageManagerHelper) {
+            super(null, packageManagerHelper);
+            mState = state;
+        }
+
+        @Override
+        boolean createIdmap(@NonNull final PackageInfo targetPackage,
+                @NonNull final PackageInfo overlayPackage, int userId) {
+            final DummyDeviceState.Package t = mState.select(targetPackage.packageName, userId);
+            if (t == null) {
+                return false;
+            }
+            final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId);
+            if (o == null) {
+                return false;
+            }
+            if (!o.canCreateIdmap) {
+                return false;
+            }
+            final String key = createKey(overlayPackage.packageName, userId);
+            mIdmapFiles.add(key);
+            return true;
+        }
+
+        @Override
+        boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
+            final String key = createKey(oi.packageName, oi.userId);
+            if (!mIdmapFiles.contains(key)) {
+                return false;
+            }
+            mIdmapFiles.remove(key);
+            return true;
+        }
+
+        @Override
+        boolean idmapExists(@NonNull final OverlayInfo oi) {
+            final String key = createKey(oi.packageName, oi.userId);
+            return mIdmapFiles.contains(key);
+        }
+
+        @Override
+        boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
+            final String key = createKey(overlayPackage.packageName, userId);
+            return mIdmapFiles.contains(key);
+        }
+
+        private String createKey(@NonNull final String packageName, final int userId) {
+            return String.format("%s:%d", packageName, userId);
+        }
+    }
+
+    private static class DummyListener implements OverlayManagerServiceImpl.OverlayChangeListener {
+        public int count;
+
+        public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
+            count++;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
new file mode 100644
index 0000000..8ff8b6e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -0,0 +1,505 @@
+/*
+ * 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.om;
+
+import static android.content.om.OverlayInfo.STATE_DISABLED;
+import static android.content.om.OverlayInfo.STATE_ENABLED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.om.OverlayInfo;
+import android.text.TextUtils;
+import android.util.Xml;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@RunWith(AndroidJUnit4.class)
+public class OverlayManagerSettingsTests {
+    private OverlayManagerSettings mSettings;
+
+    private static final OverlayInfo OVERLAY_A0 = new OverlayInfo(
+            "com.dummy.overlay_a",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_a-1/base.apk",
+            STATE_DISABLED,
+            0,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_B0 = new OverlayInfo(
+            "com.dummy.overlay_b",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_b-1/base.apk",
+            STATE_DISABLED,
+            0,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_C0 = new OverlayInfo(
+            "com.dummy.overlay_c",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_c-1/base.apk",
+            STATE_DISABLED,
+            0,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_A1 = new OverlayInfo(
+            "com.dummy.overlay_a",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_a-1/base.apk",
+            STATE_DISABLED,
+            1,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_B1 = new OverlayInfo(
+            "com.dummy.overlay_b",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_b-1/base.apk",
+            STATE_DISABLED,
+            1,
+            0,
+            false);
+
+    @Before
+    public void setUp() throws Exception {
+        mSettings = new OverlayManagerSettings();
+    }
+
+    // tests: generic functionality
+
+    @Test
+    public void testSettingsInitiallyEmpty() throws Exception {
+        final int userId = 0;
+        Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(userId);
+        assertEquals(0, map.size());
+    }
+
+    @Test
+    public void testBasicSetAndGet() throws Exception {
+        assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId);
+
+        insert(OVERLAY_A0);
+        assertContains(mSettings, OVERLAY_A0);
+        OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId);
+        assertEquals(OVERLAY_A0, oi);
+
+        assertTrue(mSettings.remove(OVERLAY_A0.packageName, OVERLAY_A0.userId));
+        assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId);
+    }
+
+    @Test
+    public void testGetUsers() throws Exception {
+        int[] users = mSettings.getUsers();
+        assertEquals(0, users.length);
+
+        insert(OVERLAY_A0);
+        users = mSettings.getUsers();
+        assertEquals(1, users.length);
+        assertContains(users, OVERLAY_A0.userId);
+
+        insert(OVERLAY_A1);
+        insert(OVERLAY_B1);
+        users = mSettings.getUsers();
+        assertEquals(2, users.length);
+        assertContains(users, OVERLAY_A0.userId);
+        assertContains(users, OVERLAY_A1.userId);
+    }
+
+    @Test
+    public void testGetOverlaysForUser() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_A1);
+        insert(OVERLAY_B1);
+
+        Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(OVERLAY_A0.userId);
+        assertEquals(1, map.keySet().size());
+        assertTrue(map.keySet().contains(OVERLAY_A0.targetPackageName));
+
+        List<OverlayInfo> list = map.get(OVERLAY_A0.targetPackageName);
+        assertEquals(2, list.size());
+        assertTrue(list.contains(OVERLAY_A0));
+        assertTrue(list.contains(OVERLAY_B0));
+
+        // getOverlaysForUser should never return null
+        map = mSettings.getOverlaysForUser(-1);
+        assertNotNull(map);
+        assertEquals(0, map.size());
+    }
+
+    @Test
+    public void testRemoveUser() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_A1);
+
+        assertContains(mSettings, OVERLAY_A0);
+        assertContains(mSettings, OVERLAY_B0);
+        assertContains(mSettings, OVERLAY_A1);
+
+        mSettings.removeUser(OVERLAY_A0.userId);
+
+        assertDoesNotContain(mSettings, OVERLAY_A0);
+        assertDoesNotContain(mSettings, OVERLAY_B0);
+        assertContains(mSettings, OVERLAY_A1);
+    }
+
+    @Test
+    public void testOrderOfNewlyAddedItems() throws Exception {
+        // new items are appended to the list
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        // overlays keep their positions when updated
+        mSettings.setState(OVERLAY_B0.packageName, OVERLAY_B0.userId, STATE_ENABLED);
+        OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_B0.packageName, OVERLAY_B0.userId);
+
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, oi, OVERLAY_C0);
+    }
+
+    @Test
+    public void testSetPriority() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        boolean changed = mSettings.setPriority(OVERLAY_B0.packageName, OVERLAY_C0.packageName,
+                OVERLAY_B0.userId);
+        assertTrue(changed);
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
+
+        changed =
+            mSettings.setPriority(OVERLAY_B0.packageName, "does.not.exist", OVERLAY_B0.userId);
+        assertFalse(changed);
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
+
+        OverlayInfo otherTarget = new OverlayInfo(
+                "com.dummy.overlay_other",
+                "com.dummy.some.other.target",
+                null,
+                "some-category",
+                "/data/app/com.dummy.overlay_other-1/base.apk",
+                STATE_DISABLED,
+                0,
+                0,
+                false);
+        insert(otherTarget);
+        changed = mSettings.setPriority(OVERLAY_A0.packageName, otherTarget.packageName,
+                OVERLAY_A0.userId);
+        assertFalse(changed);
+    }
+
+    @Test
+    public void testSetLowestPriority() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        boolean changed = mSettings.setLowestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId);
+        assertTrue(changed);
+
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_B0, OVERLAY_A0, OVERLAY_C0);
+    }
+
+    @Test
+    public void testSetHighestPriority() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        boolean changed = mSettings.setHighestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId);
+        assertTrue(changed);
+
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
+    }
+
+    // tests: persist and restore
+
+    @Test
+    public void testPersistEmpty() throws Exception {
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlTags(xml, "overlays"));
+        assertEquals(0, countXmlTags(xml, "item"));
+    }
+
+    @Test
+    public void testPersistDifferentOverlaysSameUser() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        final String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlTags(xml, "overlays"));
+        assertEquals(2, countXmlTags(xml, "item"));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName",
+                    OVERLAY_A0.packageName));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName",
+                    OVERLAY_B0.packageName));
+        assertEquals(2, countXmlAttributesWhere(xml, "item", "userId",
+                    Integer.toString(OVERLAY_A0.userId)));
+    }
+
+    @Test
+    public void testPersistSameOverlayDifferentUsers() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_A1);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlTags(xml, "overlays"));
+        assertEquals(2, countXmlTags(xml, "item"));
+        assertEquals(2, countXmlAttributesWhere(xml, "item", "packageName",
+                    OVERLAY_A0.packageName));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "userId",
+                    Integer.toString(OVERLAY_A0.userId)));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "userId",
+                    Integer.toString(OVERLAY_A1.userId)));
+    }
+
+    @Test
+    public void testPersistEnabled() throws Exception {
+        insert(OVERLAY_A0);
+        mSettings.setEnabled(OVERLAY_A0.packageName, OVERLAY_A0.userId, true);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "isEnabled", "true"));
+    }
+
+    @Test
+    public void testRestoreEmpty() throws Exception {
+        final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION;
+        final String xml =
+                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<overlays version=\"" + version + "\" />\n";
+        ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+
+        mSettings.restore(is);
+        assertDoesNotContain(mSettings, "com.dummy.overlay", 0);
+    }
+
+    @Test
+    public void testRestoreSingleUserSingleOverlay() throws Exception {
+        final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION;
+        final String xml =
+                "<?xml version='1.0' encoding='utf-8' standalone='yes'?>\n"
+                + "<overlays version='" + version + "'>\n"
+                + "<item packageName='com.dummy.overlay'\n"
+                + "      userId='1234'\n"
+                + "      targetPackageName='com.dummy.target'\n"
+                + "      baseCodePath='/data/app/com.dummy.overlay-1/base.apk'\n"
+                + "      state='" + STATE_DISABLED + "'\n"
+                + "      isEnabled='false'\n"
+                + "      category='dummy-category'\n"
+                + "      isStatic='false'\n"
+                + "      priority='0' />\n"
+                + "</overlays>\n";
+        ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+
+        mSettings.restore(is);
+        OverlayInfo oi = mSettings.getOverlayInfo("com.dummy.overlay", 1234);
+        assertNotNull(oi);
+        assertEquals("com.dummy.overlay", oi.packageName);
+        assertEquals("com.dummy.target", oi.targetPackageName);
+        assertEquals("/data/app/com.dummy.overlay-1/base.apk", oi.baseCodePath);
+        assertEquals(1234, oi.userId);
+        assertEquals(STATE_DISABLED, oi.state);
+        assertFalse(mSettings.getEnabled("com.dummy.overlay", 1234));
+    }
+
+    @Test
+    public void testPersistAndRestore() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B1);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+        ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+        OverlayManagerSettings newSettings = new OverlayManagerSettings();
+        newSettings.restore(is);
+
+        OverlayInfo a = newSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId);
+        assertEquals(OVERLAY_A0, a);
+
+        OverlayInfo b = newSettings.getOverlayInfo(OVERLAY_B1.packageName, OVERLAY_B1.userId);
+        assertEquals(OVERLAY_B1, b);
+    }
+
+    private int countXmlTags(String xml, String tagToLookFor) throws Exception {
+        int count = 0;
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new StringReader(xml));
+        int event = parser.getEventType();
+        while (event != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG && tagToLookFor.equals(parser.getName())) {
+                count++;
+            }
+            event = parser.next();
+        }
+        return count;
+    }
+
+    private int countXmlAttributesWhere(String xml, String tag, String attr, String value)
+            throws Exception {
+        int count = 0;
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new StringReader(xml));
+        int event = parser.getEventType();
+        while (event != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
+                String v = parser.getAttributeValue(null, attr);
+                if (value.equals(v)) {
+                    count++;
+                }
+            }
+            event = parser.next();
+        }
+        return count;
+    }
+
+    private void insert(OverlayInfo oi) throws Exception {
+        mSettings.init(oi.packageName, oi.userId, oi.targetPackageName, null, oi.baseCodePath,
+                false, 0, oi.category);
+        mSettings.setState(oi.packageName, oi.userId, oi.state);
+        mSettings.setEnabled(oi.packageName, oi.userId, false);
+    }
+
+    private static void assertContains(final OverlayManagerSettings settings,
+            final OverlayInfo oi) {
+        assertContains(settings, oi.packageName, oi.userId);
+    }
+
+    private static void assertContains(final OverlayManagerSettings settings,
+            final String packageName, int userId) {
+        try {
+            settings.getOverlayInfo(packageName, userId);
+        } catch (OverlayManagerSettings.BadKeyException e) {
+            fail(String.format("settings does not contain packageName=%s userId=%d",
+                        packageName, userId));
+        }
+    }
+
+    private static void assertDoesNotContain(final OverlayManagerSettings settings,
+            final OverlayInfo oi) {
+        assertDoesNotContain(settings, oi.packageName, oi.userId);
+    }
+
+    private static void assertDoesNotContain(final OverlayManagerSettings settings,
+            final String packageName, int userId) {
+        try {
+            settings.getOverlayInfo(packageName, userId);
+            fail(String.format("settings contains packageName=%s userId=%d", packageName, userId));
+        } catch (OverlayManagerSettings.BadKeyException e) {
+            // do nothing: we expect to end up here
+        }
+    }
+
+    private static void assertContains(int[] haystack, int needle) {
+        List<Integer> list = IntStream.of(haystack)
+                .boxed()
+                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+        if (!list.contains(needle)) {
+            fail(String.format("integer array [%s] does not contain value %s",
+                        TextUtils.join(",", list), needle));
+        }
+    }
+
+    private static void assertDoesNotContain(int[] haystack, int needle) {
+        List<Integer> list = IntStream.of(haystack)
+                .boxed()
+                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+        if (list.contains(needle)) {
+            fail(String.format("integer array [%s] contains value %s",
+                        TextUtils.join(",", list), needle));
+        }
+    }
+
+    private static void assertListsAreEqual(List<OverlayInfo> list, OverlayInfo... array) {
+        List<OverlayInfo> other = Stream.of(array)
+                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+        assertListsAreEqual(list, other);
+    }
+
+    private static void assertListsAreEqual(List<OverlayInfo> list, List<OverlayInfo> other) {
+        if (!list.equals(other)) {
+            fail(String.format("lists [%s] and [%s] differ",
+                        TextUtils.join(",", list), TextUtils.join(",", other)));
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 3f687c8..8cde106 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -185,6 +185,9 @@
     public void notifyZygote(boolean enableMultiProcess) {}
 
     @Override
+    public void ensureZygoteStarted() {}
+
+    @Override
     public boolean isMultiProcessDefaultEnabled() {
         return mMultiProcessDefault;
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 43fe674..8aaf29a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -23,9 +23,11 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -36,6 +38,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -61,6 +64,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
@@ -965,6 +969,62 @@
     }
 
     @Test
+    public void testOnNullBinding() throws Exception {
+        Context context = mock(Context.class);
+        PackageManager pm = mock(PackageManager.class);
+        ApplicationInfo ai = new ApplicationInfo();
+        ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+        when(context.getPackageName()).thenReturn(mContext.getPackageName());
+        when(context.getUserId()).thenReturn(mContext.getUserId());
+        when(context.getPackageManager()).thenReturn(pm);
+        when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+        ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+        service.registerSystemService(cn, 0);
+        when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            ServiceConnection sc = (ServiceConnection) args[1];
+            sc.onNullBinding(cn);
+            return true;
+        });
+
+        service.registerSystemService(cn, 0);
+        assertFalse(service.isBound(cn, 0));
+    }
+
+    @Test
+    public void testOnServiceConnected() throws Exception {
+        Context context = mock(Context.class);
+        PackageManager pm = mock(PackageManager.class);
+        ApplicationInfo ai = new ApplicationInfo();
+        ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+        when(context.getPackageName()).thenReturn(mContext.getPackageName());
+        when(context.getUserId()).thenReturn(mContext.getUserId());
+        when(context.getPackageManager()).thenReturn(pm);
+        when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+        ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+        service.registerSystemService(cn, 0);
+        when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            ServiceConnection sc = (ServiceConnection) args[1];
+            sc.onServiceConnected(cn, mock(IBinder.class));
+            return true;
+        });
+
+        service.registerSystemService(cn, 0);
+        assertTrue(service.isBound(cn, 0));
+    }
+
+    @Test
     public void testOnPackagesChanged_nullValuesPassed_noNullPointers() {
         for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
             ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ca7a71e..355ff63 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -71,8 +71,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
+import android.app.AutomaticZenRule;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
@@ -117,6 +119,7 @@
 import android.service.notification.NotificationStats;
 import android.service.notification.NotifyingApp;
 import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenPolicy;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
@@ -345,6 +348,7 @@
         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
         when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
         when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
+        when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
 
         // write to a test file; the system file isn't readable from tests
         mFile = new File(mContext.getCacheDir(), "test.xml");
@@ -2887,7 +2891,7 @@
     }
 
     @Test
-    public void testApplyEnqueuedAdjustmentFromAssistant_importance_onTime() throws Exception {
+    public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception {
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addEnqueuedNotification(r);
         NotificationManagerService.WorkerHandler handler = mock(
@@ -2905,25 +2909,6 @@
     }
 
     @Test
-    public void testApplyEnqueuedAdjustmentFromAssistant_importance_tooLate() throws Exception {
-        final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
-        mService.addNotification(r);
-        NotificationManagerService.WorkerHandler handler = mock(
-                NotificationManagerService.WorkerHandler.class);
-        mService.setHandler(handler);
-        when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
-
-        Bundle signals = new Bundle();
-        signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
-        Adjustment adjustment = new Adjustment(
-                r.sbn.getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
-        mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
-
-        assertEquals(IMPORTANCE_DEFAULT, r.getImportance());
-        assertFalse(r.hasAdjustment(KEY_IMPORTANCE));
-    }
-
-    @Test
     public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception {
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addEnqueuedNotification(r);
@@ -4305,6 +4290,36 @@
     }
 
     @Test
+    public void testFlagBubble() throws RemoteException {
+        // Bubbles are allowed!
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+        when(mPreferencesHelper.getNotificationChannel(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+                mTestNotificationChannel);
+        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+                mTestNotificationChannel.getImportance());
+
+        // Notif with bubble metadata but not our other misc requirements
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
+                null /* tvExtender */, true /* isBubble */);
+
+        // Say we're foreground
+        when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
+                IMPORTANCE_FOREGROUND);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+        assertEquals(1, notifs.length);
+        assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0);
+        assertTrue(mService.getNotificationRecord(
+                nr.sbn.getKey()).getNotification().isBubbleNotification());
+    }
+
+    @Test
     public void testFlagBubbleNotifs_flag_appForeground() throws RemoteException {
         // Bubbles are allowed!
         mService.setPreferencesHelper(mPreferencesHelper);
@@ -4934,22 +4949,26 @@
         assertEquals(1, mService.getNotificationRecordCount());
     }
 
-    public void testGetAllowedAssistantCapabilities() throws Exception {
-        List<String> capabilities = mBinderService.getAllowedAssistantCapabilities(null);
+    @Test
+    public void testGetAllowedAssistantAdjustments() throws Exception {
+        List<String> capabilities = mBinderService.getAllowedAssistantAdjustments(null);
         assertNotNull(capabilities);
 
         for (int i = capabilities.size() - 1; i >= 0; i--) {
             String capability = capabilities.get(i);
-            mBinderService.disallowAssistantCapability(capability);
-            assertEquals(i + 1, mBinderService.getAllowedAssistantCapabilities(null).size());
-            List<String> currentCapabilities = mBinderService.getAllowedAssistantCapabilities(null);
+            mBinderService.disallowAssistantAdjustment(capability);
+            assertEquals(i + 1, mBinderService.getAllowedAssistantAdjustments(null).size());
+            List<String> currentCapabilities = mBinderService.getAllowedAssistantAdjustments(null);
             assertNotNull(currentCapabilities);
             assertFalse(currentCapabilities.contains(capability));
         }
     }
 
+    @Test
     public void testAdjustRestrictedKey() throws Exception {
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+        mService.addNotification(r);
+        when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
 
         when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true);
         when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false);
@@ -4967,6 +4986,34 @@
         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
     }
 
+    @Test
+    public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception {
+        when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+                .thenReturn(true);
+        mService.setZenHelper(mock(ZenModeHelper.class));
+        ComponentName owner = new ComponentName(mContext, this.getClass());
+        ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+        boolean isEnabled = true;
+        AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
+
+        try {
+            mBinderService.addAutomaticZenRule(rule);
+            fail("Zen policy only applies to priority only mode");
+        } catch (IllegalArgumentException e) {
+            // yay
+        }
+
+        rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+        mBinderService.addAutomaticZenRule(rule);
+
+        rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
+        mBinderService.addAutomaticZenRule(rule);
+    }
+
+    @Test
     public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
         try {
             mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
@@ -4983,6 +5030,7 @@
                 mUid + UserHandle.PER_USER_RANGE);
     }
 
+    @Test
     public void testAreBubblesAllowedForPackage_crossUser() throws Exception {
         try {
             mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(),
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 6ed78b3..b34bd25 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -940,12 +940,12 @@
     @Test
     public void testClearLockedFields() {
         final NotificationChannel channel = getChannel();
-        mHelper.clearLockedFields(channel);
+        mHelper.clearLockedFieldsLocked(channel);
         assertEquals(0, channel.getUserLockedFields());
 
         channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
                 | NotificationChannel.USER_LOCKED_IMPORTANCE);
-        mHelper.clearLockedFields(channel);
+        mHelper.clearLockedFieldsLocked(channel);
         assertEquals(0, channel.getUserLockedFields());
     }
 
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 32e96a5..44390b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -57,6 +57,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
 import android.util.MutableBoolean;
+import android.view.DisplayInfo;
 
 import androidx.test.filters.MediumTest;
 
@@ -87,6 +88,10 @@
 
         doReturn(false).when(mService).isBooting();
         doReturn(true).when(mService).isBooted();
+
+        final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
+        doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy();
+        doReturn(mock(DisplayInfo.class)).when(displayContent).getDisplayInfo();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index d02db7b..44aa55d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -659,7 +659,7 @@
             boolean hasForegroundActivities, boolean callerIsRecents,
             boolean callerIsTempWhitelisted,
             boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
-            boolean isCallingPackageNameDeviceOwner, boolean isCallingPackageTempWhitelisted) {
+            boolean isCallingUidDeviceOwner, boolean isCallingPackageTempWhitelisted) {
         // window visibility
         doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
                 .isAnyNonToastWindowVisibleForUid(callingUid);
@@ -685,8 +685,8 @@
         // caller is instrumenting with background activity starts privileges
         callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
                 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
-        // calling package name is the device owner
-        doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any());
+        // callingUid is the device owner
+        doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
         // calling package name is temporarily whitelisted
         doReturn(isCallingPackageTempWhitelisted).when(mService)
                 .isPackageNameWhitelistedForBgActivityStarts("com.whatever.dude");
diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 9ce5795..beec1a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -18,6 +18,8 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.server.wm.BoundsAnimationController.BOUNDS;
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -131,6 +133,8 @@
         boolean mCancelRequested;
         Rect mStackBounds;
         Rect mTaskBounds;
+        float mAlpha;
+        @BoundsAnimationController.AnimationType int mAnimationType;
 
         void initialize(Rect from) {
             mAwaitingAnimationStart = true;
@@ -148,11 +152,12 @@
 
         @Override
         public boolean onAnimationStart(boolean schedulePipModeChangedCallback,
-                boolean forceUpdate) {
+                boolean forceUpdate, @BoundsAnimationController.AnimationType int animationType) {
             mAwaitingAnimationStart = false;
             mAnimationStarted = true;
             mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback;
             mForcePipModeChangedCallback = forceUpdate;
+            mAnimationType = animationType;
             return true;
         }
 
@@ -185,6 +190,12 @@
             mMovedToFullscreen = moveToFullscreen;
             mTaskBounds = null;
         }
+
+        @Override
+        public boolean setPinnedStackAlpha(float alpha) {
+            mAlpha = alpha;
+            return true;
+        }
     }
 
     /**
@@ -201,6 +212,7 @@
         private Rect mTo;
         private Rect mLargerBounds;
         private Rect mExpectedFinalBounds;
+        private @BoundsAnimationController.AnimationType int mAnimationType;
 
         BoundsAnimationDriver(BoundsAnimationController controller,
                 TestBoundsAnimationTarget target, MockValueAnimator mockValueAnimator) {
@@ -209,7 +221,8 @@
             mMockAnimator = mockValueAnimator;
         }
 
-        BoundsAnimationDriver start(Rect from, Rect to) {
+        BoundsAnimationDriver start(Rect from, Rect to,
+                @BoundsAnimationController.AnimationType int animationType) {
             if (mAnimator != null) {
                 throw new IllegalArgumentException("Call restart() to restart an animation");
             }
@@ -223,7 +236,7 @@
             assertTrue(mTarget.mAwaitingAnimationStart);
             assertFalse(mTarget.mAnimationStarted);
 
-            startImpl(from, to);
+            startImpl(from, to, animationType);
 
             // Ensure that the animator is paused for the all windows drawn signal when animating
             // to/from fullscreen
@@ -253,7 +266,7 @@
             mTarget.mAnimationStarted = false;
 
             // Start animation
-            startImpl(mTarget.mStackBounds, to);
+            startImpl(mTarget.mStackBounds, to, BOUNDS);
 
             if (toSameBounds) {
                 // Same animator if same final bounds
@@ -273,13 +286,15 @@
             return this;
         }
 
-        private BoundsAnimationDriver startImpl(Rect from, Rect to) {
+        private BoundsAnimationDriver startImpl(Rect from, Rect to,
+                @BoundsAnimationController.AnimationType int animationType) {
             boolean fromFullscreen = from.equals(BOUNDS_FULL);
             boolean toFullscreen = to.equals(BOUNDS_FULL);
             mFrom = new Rect(from);
             mTo = new Rect(to);
             mExpectedFinalBounds = new Rect(to);
             mLargerBounds = getLargerBounds(mFrom, mTo);
+            mAnimationType = animationType;
 
             // Start animation
             final @SchedulePipModeChangedState int schedulePipModeChangedState = toFullscreen
@@ -288,17 +303,19 @@
                             ? SCHEDULE_PIP_MODE_CHANGED_ON_END
                             : NO_PIP_MODE_CHANGED_CALLBACKS;
             mAnimator = mController.animateBoundsImpl(mTarget, from, to, DURATION,
-                    schedulePipModeChangedState, fromFullscreen, toFullscreen);
+                    schedulePipModeChangedState, fromFullscreen, toFullscreen, animationType);
 
-            // Original stack bounds, frozen task bounds
-            assertEquals(mFrom, mTarget.mStackBounds);
-            assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
+            if (animationType == BOUNDS) {
+                // Original stack bounds, frozen task bounds
+                assertEquals(mFrom, mTarget.mStackBounds);
+                assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
 
-            // Animating to larger size
-            if (mFrom.equals(mLargerBounds)) {
-                assertFalse(mAnimator.animatingToLargerSize());
-            } else if (mTo.equals(mLargerBounds)) {
-                assertTrue(mAnimator.animatingToLargerSize());
+                // Animating to larger size
+                if (mFrom.equals(mLargerBounds)) {
+                    assertFalse(mAnimator.animatingToLargerSize());
+                } else if (mTo.equals(mLargerBounds)) {
+                    assertTrue(mAnimator.animatingToLargerSize());
+                }
             }
 
             return this;
@@ -315,16 +332,20 @@
         BoundsAnimationDriver update(float t) {
             mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(t));
 
-            // Temporary stack bounds, frozen task bounds
-            if (t == 0f) {
-                assertEquals(mFrom, mTarget.mStackBounds);
-            } else if (t == 1f) {
-                assertEquals(mTo, mTarget.mStackBounds);
+            if (mAnimationType == BOUNDS) {
+                // Temporary stack bounds, frozen task bounds
+                if (t == 0f) {
+                    assertEquals(mFrom, mTarget.mStackBounds);
+                } else if (t == 1f) {
+                    assertEquals(mTo, mTarget.mStackBounds);
+                } else {
+                    assertNotEquals(mFrom, mTarget.mStackBounds);
+                    assertNotEquals(mTo, mTarget.mStackBounds);
+                }
+                assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
             } else {
-                assertNotEquals(mFrom, mTarget.mStackBounds);
-                assertNotEquals(mTo, mTarget.mStackBounds);
+                assertEquals((float) mMockAnimator.getAnimatedValue(), mTarget.mAlpha, 0.01f);
             }
-            assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
             return this;
         }
 
@@ -353,10 +374,14 @@
         BoundsAnimationDriver end() {
             mAnimator.end();
 
-            // Final stack bounds
-            assertEquals(mTo, mTarget.mStackBounds);
-            assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds);
-            assertNull(mTarget.mTaskBounds);
+            if (mAnimationType == BOUNDS) {
+                // Final stack bounds
+                assertEquals(mTo, mTarget.mStackBounds);
+                assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds);
+                assertNull(mTarget.mTaskBounds);
+            } else {
+                assertEquals(mTarget.mAlpha, 1f, 0.01f);
+            }
 
             return this;
         }
@@ -413,7 +438,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingTransition() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -425,7 +450,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenTransition() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -437,7 +462,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToSmallerFloatingTransition() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -449,7 +474,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToLargerFloatingTransition() {
-        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -463,7 +488,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingCancelFromTarget() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
@@ -473,7 +498,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingCancelFromAnimationToSameBounds() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_FLOATING, false /* expectStartedAndPipModeChangedCallback */)
@@ -484,7 +509,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_SMALLER_FLOATING,
@@ -498,7 +523,7 @@
     public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() {
         // When animating from fullscreen and the animation is interruped, we expect the animation
         // start callback to be made, with a forced pip mode change callback
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_FULL, true /* expectStartedAndPipModeChangedCallback */)
@@ -511,7 +536,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenCancelFromTarget() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
@@ -521,7 +546,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenCancelFromAnimationToSameBounds() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_FULL, false /* expectStartedAndPipModeChangedCallback */)
@@ -532,7 +557,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_SMALLER_FLOATING,
@@ -546,7 +571,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToSmallerFloatingCancelFromTarget() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
@@ -556,13 +581,25 @@
     @UiThreadTest
     @Test
     public void testFloatingToLargerFloatingCancelFromTarget() {
-        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
                 .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
     }
 
+    @UiThreadTest
+    @Test
+    public void testFadeIn() {
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, FADE_IN)
+                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
+                .update(0f)
+                .update(0.5f)
+                .update(1f)
+                .end()
+                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
+    }
+
     /** MISC **/
 
     @UiThreadTest
@@ -570,7 +607,7 @@
     public void testBoundsAreCopied() {
         Rect from = new Rect(0, 0, 100, 100);
         Rect to = new Rect(25, 25, 75, 75);
-        mDriver.start(from, to)
+        mDriver.start(from, to, BOUNDS)
                 .update(0.25f)
                 .end();
         assertEquals(new Rect(0, 0, 100, 100), from);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index e392353..0c2ce61 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -163,7 +163,7 @@
         // Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot
         // animation.
         mController.mRecentScreenshotAnimator.cancelAnimation();
-        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true);
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
     }
 
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 5625ea4..f615823 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -71,6 +71,7 @@
     @Test
     public void testCancelAnimationOnVisibleStackOrderChange() {
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
         ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         new ActivityBuilder(mService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 2377df4..9cdb465 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -19,16 +19,14 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 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.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.TaskPositioner.MIN_ASPECT;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -39,9 +37,9 @@
 import android.util.Log;
 import android.view.Display;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -53,7 +51,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest
 public class TaskPositionerTests extends WindowTestsBase {
 
     private static final boolean DEBUGGING = false;
@@ -66,10 +63,9 @@
     private int mMinVisibleHeight;
     private TaskPositioner mPositioner;
     private WindowState mWindow;
-    private Rect mDimBounds = new Rect();
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         TaskPositioner.setFactory(null);
 
         final Display display = mDisplayContent.getDisplay();
@@ -84,17 +80,16 @@
         mPositioner.register(mDisplayContent);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
-        final Task task = mWindow.getTask();
-        spyOn(task);
-        doAnswer(invocation -> {
-            final Rect rect = (Rect) invocation.getArguments()[0];
-            rect.set(mDimBounds);
-            return null;
-        }).when(task).getDimBounds(any(Rect.class));
-
+        mPositioner.mTask = mWindow.getTask();
         mWindow.getStack().setWindowingMode(WINDOWING_MODE_FREEFORM);
     }
 
+    @After
+    public void tearDown() {
+        mWindow = null;
+        mPositioner = null;
+    }
+
     @Test
     public void testOverrideFactory() {
         final boolean[] created = new boolean[1];
@@ -119,11 +114,11 @@
     public void testBasicFreeWindowResizing() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         // Start a drag resize starting upper left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         assertBoundsEquals(r, mPositioner.getWindowDragBounds());
 
         // Drag to a good landscape size.
@@ -149,8 +144,8 @@
                 mPositioner.getWindowDragBounds());
 
         // Start a drag resize left and see that only the left coord changes..
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -181,77 +176,77 @@
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         // Drag upper left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, 0.0f);
-        assertTrue(r.left != mPositioner.getWindowDragBounds().left);
+        assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
-        assertTrue(r.top != mPositioner.getWindowDragBounds().top);
+        assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag upper.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, midX, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
-        assertTrue(r.top != mPositioner.getWindowDragBounds().top);
+        assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag upper right.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
-        assertTrue(r.right != mPositioner.getWindowDragBounds().right);
-        assertTrue(r.top != mPositioner.getWindowDragBounds().top);
+        assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
+        assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag right.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.right + MOUSE_DELTA_X, midY);
         mPositioner.resizeDrag(r.right + 100, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
-        assertTrue(r.right != mPositioner.getWindowDragBounds().right);
+        assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom right.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/,
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */,
                 r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
-        assertTrue(r.right != mPositioner.getWindowDragBounds().right);
+        assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
-        assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
+        assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, midX, r.bottom + MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, midX, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
-        assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
+        assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, r.bottom + 100);
-        assertTrue(r.left != mPositioner.getWindowDragBounds().left);
+        assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
-        assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
+        assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midX);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
         mPositioner.resizeDrag(0.0f, r.bottom + 100);
-        assertTrue(r.left != mPositioner.getWindowDragBounds().left);
+        assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
@@ -264,10 +259,10 @@
     @Test
     public void testLandscapePreservedWindowResizingDragTopLeft() {
         final Rect r = new Rect(100, 220, 700, 520);
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         assertBoundsEquals(r, mPositioner.getWindowDragBounds());
 
         // Drag to a good landscape size.
@@ -303,10 +298,10 @@
     public void testLandscapePreservedWindowResizingDragLeft() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -344,7 +339,7 @@
     public void testLandscapePreservedWindowResizingDragTop() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         mPositioner.startDrag(mWindow, true /*resizing*/,
                 true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
@@ -380,7 +375,7 @@
     @Test
     public void testPortraitPreservedWindowResizingDragTopLeft() {
         final Rect r = new Rect(330, 100, 630, 600);
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         mPositioner.startDrag(mWindow, true /*resizing*/,
                 true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
@@ -414,10 +409,10 @@
     public void testPortraitPreservedWindowResizingDragLeft() {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -457,10 +452,10 @@
     public void testPortraitPreservedWindowResizingDragTop() {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midX = (r.left + r.right) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, midX, r.top - MOUSE_DELTA_Y);
 
         // Drag to the left (no change).
         mPositioner.resizeDrag(0.0f, r.top);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index dc307b5..d87eed2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -25,7 +25,10 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Surface.ROTATION_0;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.hamcrest.Matchers.not;
@@ -35,6 +38,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManager;
@@ -357,6 +362,7 @@
         parentConfig.densityDpi = 400;
         parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
         parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
+        parentConfig.windowConfiguration.setRotation(ROTATION_0);
 
         // Portrait bounds.
         inOutConfig.windowConfiguration.getBounds().set(0, 0, shortSide, longSide);
@@ -370,12 +376,27 @@
         inOutConfig.setToDefaults();
         // Landscape bounds.
         inOutConfig.windowConfiguration.getBounds().set(0, 0, longSide, shortSide);
+
+        // Setup the display with a top stable inset. The later assertion will ensure the inset is
+        // excluded from screenHeightDp.
+        final int statusBarHeight = 100;
+        final DisplayContent displayContent = mock(DisplayContent.class);
+        final DisplayPolicy policy = mock(DisplayPolicy.class);
+        doAnswer(invocationOnMock -> {
+            final Rect insets = invocationOnMock.<Rect>getArgument(0);
+            insets.top = statusBarHeight;
+            return null;
+        }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
+        doReturn(policy).when(displayContent).getDisplayPolicy();
+        doReturn(mock(DisplayInfo.class)).when(displayContent).getDisplayInfo();
+
         // Without limiting to be inside the parent bounds, the out screen size should keep relative
         // to the input bounds.
-        task.computeConfigResourceOverrides(inOutConfig, parentConfig,
-                false /* insideParentBounds */);
+        final ActivityRecord.CompatDisplayInsets compatIntsets =
+                new ActivityRecord.CompatDisplayInsets(displayContent);
+        task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
 
-        assertEquals(shortSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+        assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
                 inOutConfig.screenHeightDp);
         assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
                 inOutConfig.screenWidthDp);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index ca815ec..cb6dc6d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 
+import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.ComponentName;
 import android.graphics.Canvas;
@@ -38,7 +39,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.view.Surface;
 import android.view.SurfaceControl;
 
 import androidx.test.filters.SmallTest;
@@ -67,8 +67,17 @@
                 ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */,
                 WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */);
         mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
-                Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
-                ORIENTATION_PORTRAIT);
+                createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
+                taskBounds, ORIENTATION_PORTRAIT);
+    }
+
+    private static TaskDescription createTaskDescription(int background, int statusBar,
+            int navigationBar) {
+        final TaskDescription td = new TaskDescription();
+        td.setBackgroundColor(background);
+        td.setStatusBarColor(statusBar);
+        td.setNavigationBarColor(navigationBar);
+        return td;
     }
 
     private void setupSurface(int width, int height) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 1eb716a..9722d2c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -207,7 +207,8 @@
 
         // Test for onTaskMovedToFront.
         assertEquals(1, taskMovedToFrontLatch.getCount());
-        mService.moveTaskToFront(id, 0, null);
+        mService.moveTaskToFront(null, getInstrumentation().getContext().getPackageName(), id, 0,
+                null);
         waitForCallback(taskMovedToFrontLatch);
         assertEquals(activity.getTaskId(), params[0]);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
index 897f0a2..0330de8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
@@ -22,6 +22,8 @@
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
@@ -70,7 +72,8 @@
                 mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM,
                 true /* isAppAnimation */, 0 /* windowCornerRadius */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
-        verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
+        verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+                argThat(rect -> rect.equals(mStackBounds)));
     }
 
     @Test
@@ -80,7 +83,8 @@
                 new Point(20, 40), mStackBounds, false /* canSkipFirstFrame */,
                 STACK_CLIP_AFTER_ANIM, true /* isAppAnimation */, 0 /* windowCornerRadius */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
-        verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
+        verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+                argThat(rect -> rect.equals(mStackBounds)));
     }
 
     @Test
@@ -121,6 +125,17 @@
     }
 
     @Test
+    public void testApply_setCornerRadius_noClip() {
+        final float windowCornerRadius = 30f;
+        WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
+                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE,
+                true /* isAppAnimation */, windowCornerRadius);
+        when(mAnimation.hasRoundedCorners()).thenReturn(true);
+        windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+        verify(mTransaction, never()).setCornerRadius(any(), anyFloat());
+    }
+
+    @Test
     public void testApply_clipBeforeSmallerAnimationClip() {
         // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 5, 5)
         Rect windowCrop = new Rect(0, 0, 5, 5);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ad1e3ef..4d7ae73 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1238,6 +1238,9 @@
 
             RoleObserver(@NonNull @CallbackExecutor Executor executor) {
                 mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
+                UserHandle currentUser = UserHandle.of(LocalServices.getService(
+                        ActivityManagerInternal.class).getCurrentUserId());
+                onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser);
             }
 
             private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) {
@@ -1285,7 +1288,9 @@
                     // Try to set role holder as VoiceInteractionService
                     List<ResolveInfo> services = mPm.queryIntentServicesAsUser(
                             new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg),
-                            PackageManager.GET_META_DATA, userId);
+                            PackageManager.GET_META_DATA
+                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
 
                     for (ResolveInfo resolveInfo : services) {
                         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -1318,7 +1323,9 @@
                     // If no service could be found try to set assist activity
                     final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
                             new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
-                            PackageManager.MATCH_DEFAULT_ONLY, userId);
+                            PackageManager.MATCH_DEFAULT_ONLY
+                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
 
                     for (ResolveInfo resolveInfo : activities) {
                         ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -1331,6 +1338,7 @@
                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.VOICE_RECOGNITION_SERVICE,
                                 getDefaultRecognizer(user), userId);
+                        return;
                     }
                 }
             }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 8d2cbca..ea52377 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -25,9 +25,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
-
-import com.android.internal.app.IVoiceActionCheckCallback;
-import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.content.BroadcastReceiver;
@@ -51,15 +48,16 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 
+import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
@@ -358,6 +356,7 @@
         intent.setComponent(mComponent);
         mBound = mContext.bindServiceAsUser(intent, mConnection,
                 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+                | Context.BIND_INCLUDE_CAPABILITIES
                 | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
         if (!mBound) {
             Slog.w(TAG, "Failed binding to voice interaction service " + mComponent);
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index 37fab09..36c6377 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -119,18 +119,18 @@
      * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
      * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
-     * @param handle the new phone number to dial
+     * @param gatewayUri the gateway uri for call redirection.
      * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
      * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
      *                     if the confirmFirst is true, and if the redirection request of this
      *                     response was sent with a true flag of allowInteractiveResponse via
      *                     {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
      */
-    public final void redirectCall(@NonNull Uri handle,
+    public final void redirectCall(@NonNull Uri gatewayUri,
                                    @NonNull PhoneAccountHandle targetPhoneAccount,
                                    boolean confirmFirst) {
         try {
-            mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
+            mCallRedirectionAdapter.redirectCall(gatewayUri, targetPhoneAccount, confirmFirst);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 52e0ebd..2d8a8cb 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -4321,6 +4321,22 @@
          * @hide
          */
         public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
+
+        /**
+         * The current registered raw data network operator name in long alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
+         * @hide
+         */
+        public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
+
+        /**
+         * The current registered raw data network operator name in short alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
+         * @hide
+         */
+        public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
     }
 
     /**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0f8f873..9f6528b 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1312,6 +1312,24 @@
             "hide_lte_plus_data_icon_bool";
 
     /**
+     * The string is used to filter redundant string from PLMN Network Name that's supplied by
+     * specific carrier.
+     *
+     * @hide
+     */
+    public static final String KEY_OPERATOR_NAME_FILTER_PATTERN_STRING =
+            "operator_name_filter_pattern_string";
+
+    /**
+     * The string is used to compare with operator name. If it matches the pattern then show
+     * specific data icon.
+     *
+     * @hide
+     */
+    public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING =
+            "show_carrier_data_icon_pattern_string";
+
+    /**
      * Boolean to decide whether to show precise call failed cause to user
      * @hide
      */
@@ -2803,6 +2821,19 @@
     public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL =
             "key_is_opportunistic_subscription_bool";
 
+    /**
+     * A list of 4 GSM RSSI thresholds above which a signal level is considered POOR,
+     * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
+     *
+     * Note that the min and max thresholds are fixed at -113 and -51, as set in 3GPP TS 27.007
+     * section 8.5.
+     * <p>
+     * See CellSignalStrengthGsm#GSM_RSSI_MAX and CellSignalStrengthGsm#GSM_RSSI_MIN. Any signal
+     * level outside these boundaries is considered invalid.
+     * @hide
+     */
+    public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY =
+            "gsm_rssi_thresholds_int_array";
 
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
@@ -3139,6 +3170,8 @@
         sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false);
+        sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, "");
+        sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
         sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
@@ -3204,6 +3237,13 @@
                 false);
         sDefaults.putString(KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
         sDefaults.putBoolean(KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
+        sDefaults.putIntArray(KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY,
+                new int[] {
+                        -107, /* SIGNAL_STRENGTH_POOR */
+                        -103, /* SIGNAL_STRENGTH_MODERATE */
+                        -97, /* SIGNAL_STRENGTH_GOOD */
+                        -89,  /* SIGNAL_STRENGTH_GREAT */
+                });
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 3745277..3087516 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -49,10 +49,10 @@
 
     // long alpha Operator Name String or Enhanced Operator Name String
     /** @hide */
-    protected final String mAlphaLong;
+    protected String mAlphaLong;
     // short alpha Operator Name String or Enhanced Operator Name String
     /** @hide */
-    protected final String mAlphaShort;
+    protected String mAlphaShort;
 
     /** @hide */
     protected CellIdentity(String tag, int type, String mcc, String mnc, String alphal,
@@ -145,6 +145,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setOperatorAlphaLong(String alphaLong) {
+        mAlphaLong = alphaLong;
+    }
+
+    /**
      * @return The short alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string).  May be null if unknown.
      */
@@ -154,6 +161,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setOperatorAlphaShort(String alphaShort) {
+        mAlphaShort = alphaShort;
+    }
+
+    /**
      * @return a CellLocation object for this CellIdentity
      * @hide
      */
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 5e44bf2..864540d 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -166,6 +166,7 @@
     /**
      * @return Mobile Country Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -173,6 +174,7 @@
     /**
      * @return Mobile Network Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 2dd72d6..14503c7 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -187,6 +187,7 @@
     /**
      * @return Mobile Country Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -194,6 +195,7 @@
     /**
      * @return Mobile Network Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index a591bd1..937de70 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -104,6 +104,7 @@
      * Get Mobile Country Code in string format
      * @return Mobile Country Code in string format, null if unknown
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -112,6 +113,7 @@
      * Get Mobile Network Code in string format
      * @return Mobile Network Code in string format, null if unknown
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 674c40c..b4a2ead 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -150,6 +150,7 @@
     /**
      * @return Mobile Country Code in string version, null if unavailable.
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -157,6 +158,7 @@
     /**
      * @return Mobile Network Code in string version, null if unavailable.
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index a4570e4..30b131f 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -76,18 +77,25 @@
                 new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
     }
 
+    /**
+     * @return a {@link CellIdentityCdma} instance.
+     */
     @Override
-    public CellIdentityCdma getCellIdentity() {
+    public @NonNull CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
     }
+
     /** @hide */
     @UnsupportedAppUsage
     public void setCellIdentity(CellIdentityCdma cid) {
         mCellIdentityCdma = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthCdma} instance.
+     */
     @Override
-    public CellSignalStrengthCdma getCellSignalStrength() {
+    public @NonNull CellSignalStrengthCdma getCellSignalStrength() {
         return mCellSignalStrengthCdma;
     }
 
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ce32bc1..137f97e 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -71,17 +72,24 @@
         mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
+    /**
+     * @return a {@link CellIdentityGsm} instance.
+     */
     @Override
-    public CellIdentityGsm getCellIdentity() {
+    public @NonNull CellIdentityGsm getCellIdentity() {
         return mCellIdentityGsm;
     }
+
     /** @hide */
     public void setCellIdentity(CellIdentityGsm cid) {
         mCellIdentityGsm = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthGsm} instance.
+     */
     @Override
-    public CellSignalStrengthGsm getCellSignalStrength() {
+    public @NonNull CellSignalStrengthGsm getCellSignalStrength() {
         return mCellSignalStrengthGsm;
     }
 
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 01ee20a..da7b7ab 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -79,11 +80,15 @@
         mCellConfig = new CellConfigLte(cil.cellConfig);
     }
 
+    /**
+     * @return a {@link CellIdentityLte} instance.
+     */
     @Override
-    public CellIdentityLte getCellIdentity() {
+    public @NonNull CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
         return mCellIdentityLte;
     }
+
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setCellIdentity(CellIdentityLte cid) {
@@ -91,8 +96,11 @@
         mCellIdentityLte = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthLte} instance.
+     */
     @Override
-    public CellSignalStrengthLte getCellSignalStrength() {
+    public @NonNull CellSignalStrengthLte getCellSignalStrength() {
         if (DBG) log("getCellSignalStrength: " + mCellSignalStrengthLte);
         return mCellSignalStrengthLte;
     }
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index ba4a907..9775abd 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -43,12 +43,18 @@
         mCellSignalStrength = other.mCellSignalStrength;
     }
 
+    /**
+     * @return a {@link CellIdentityNr} instance.
+     */
     @Override
     @NonNull
     public CellIdentity getCellIdentity() {
         return mCellIdentity;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthNr} instance.
+     */
     @Override
     @NonNull
     public CellSignalStrength getCellSignalStrength() {
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index ccafda6..f1305f5 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -75,6 +75,9 @@
         mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
     }
 
+    /**
+     * @return a {@link CellIdentityTdscdma} instance.
+     */
     @Override
     public @NonNull CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
@@ -85,6 +88,9 @@
         mCellIdentityTdscdma = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthTdscdma} instance.
+     */
     @Override
     public @NonNull CellSignalStrengthTdscdma getCellSignalStrength() {
         return mCellSignalStrengthTdscdma;
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index 1b32178..ee5fec8 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -71,15 +71,22 @@
         mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
     }
 
+    /**
+     * @return a {@link CellIdentityWcdma} instance.
+     */
     @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
     }
+
     /** @hide */
     public void setCellIdentity(CellIdentityWcdma cid) {
         mCellIdentityWcdma = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthWcdma} instance.
+     */
     @Override
     public CellSignalStrengthWcdma getCellSignalStrength() {
         return mCellSignalStrengthWcdma;
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index 740b970..e65b048ec 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.os.PersistableBundle;
 
 /**
@@ -57,23 +58,24 @@
     public abstract void setDefaultValues();
 
     /**
-     * Get signal level as an int from 0..4
-     * <p>
-     * @see #SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-     * @see #SIGNAL_STRENGTH_POOR
-     * @see #SIGNAL_STRENGTH_MODERATE
-     * @see #SIGNAL_STRENGTH_GOOD
-     * @see #SIGNAL_STRENGTH_GREAT
+     * Retrieve an abstract level value for the overall signal quality.
+     *
+     * @return a single integer from 0 to 4 representing the general signal quality.
+     *     0 represents very poor or unknown signal quality while 4 represents excellent
+     *     signal quality.
      */
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public abstract int getLevel();
 
     /**
-     * Get the signal level as an asu value between 0..31, 99 is unknown
+     * Get the technology-specific signal strength in Arbitrary Strength Units, calculated from the
+     * strength of the pilot signal or equivalent.
      */
     public abstract int getAsuLevel();
 
     /**
-     * Get the signal strength as dBm
+     * Get the technology-specific signal strength in dBm, which is the signal strength of the
+     * pilot signal or equivalent.
      */
     public abstract int getDbm();
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 5b19599..1998439 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -114,13 +115,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 0aeb0f6..14ae689 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -37,6 +38,10 @@
     private static final int GSM_RSSI_GOOD = -97;
     private static final int GSM_RSSI_MODERATE = -103;
     private static final int GSM_RSSI_POOR = -107;
+    private static final int GSM_RSSI_MIN = -113;
+
+    private static final int[] sRssiThresholds = new int[] {
+            GSM_RSSI_POOR, GSM_RSSI_MODERATE, GSM_RSSI_GOOD, GSM_RSSI_GREAT};
 
     private int mRssi; // in dBm [-113, -51] or UNAVAILABLE
     @UnsupportedAppUsage
@@ -53,7 +58,7 @@
 
     /** @hide */
     public CellSignalStrengthGsm(int rssi, int ber, int ta) {
-        mRssi = inRangeOrUnavailable(rssi, -113, -51);
+        mRssi = inRangeOrUnavailable(rssi, GSM_RSSI_MIN, GSM_RSSI_MAX);
         mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99);
         mTimingAdvance = inRangeOrUnavailable(ta, 0, 219);
         updateLevel(null, null);
@@ -97,13 +102,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
@@ -111,12 +112,22 @@
     /** @hide */
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        if (mRssi > GSM_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (mRssi >= GSM_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
-        else if (mRssi >= GSM_RSSI_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
-        else if (mRssi >= GSM_RSSI_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
-        else if (mRssi >= GSM_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
-        else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        int[] rssiThresholds;
+        if (cc == null) {
+            rssiThresholds = sRssiThresholds;
+        } else {
+            rssiThresholds = cc.getIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY);
+            if (rssiThresholds == null || rssiThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
+                rssiThresholds = sRssiThresholds;
+            }
+        }
+        int level = NUM_SIGNAL_STRENGTH_THRESHOLDS;
+        if (mRssi < GSM_RSSI_MIN || mRssi > GSM_RSSI_MAX) {
+            mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+            return;
+        }
+        while (level > 0 && mRssi < rssiThresholds[level - 1]) level--;
+        mLevel = level;
     }
 
     /**
@@ -141,7 +152,7 @@
     /**
      * Get the RSSI in ASU.
      *
-     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     * Asu is calculated based on 3GPP RSSI. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
      * @return RSSI in ASU 0..31, 99, or UNAVAILABLE
      */
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 5687ada..2272dc9 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -145,13 +146,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index fff3adf..1912c60 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -183,7 +184,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
@@ -227,6 +230,9 @@
         return asuLevel;
     }
 
+    /**
+     * Get the CSI-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     */
     @Override
     public int getDbm() {
         return mCsiRsrp;
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index ddbd851..f4a3dbb 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -34,14 +35,14 @@
     private static final String LOG_TAG = "CellSignalStrengthTdscdma";
     private static final boolean DBG = false;
 
-    private static final int TDSCDMA_RSSI_MAX = -51;
-    private static final int TDSCDMA_RSSI_GREAT = -77;
-    private static final int TDSCDMA_RSSI_GOOD = -87;
-    private static final int TDSCDMA_RSSI_MODERATE = -97;
-    private static final int TDSCDMA_RSSI_POOR = -107;
-
-    private static final int TDSCDMA_RSCP_MIN = -120;
+    // These levels are arbitrary but carried over from SignalStrength.java for consistency.
     private static final int TDSCDMA_RSCP_MAX = -24;
+    private static final int TDSCDMA_RSCP_GREAT = -49;
+    private static final int TDSCDMA_RSCP_GOOD = -73;
+    private static final int TDSCDMA_RSCP_MODERATE = -97;
+    private static final int TDSCDMA_RSCP_POOR = -110;
+    private static final int TDSCDMA_RSCP_MIN = -120;
+
 
     private int mRssi; // in dBm [-113, -51], CellInfo.UNAVAILABLE
 
@@ -121,13 +122,10 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = 0, to = 4)
     public int getLevel() {
         return mLevel;
     }
@@ -135,16 +133,16 @@
     /** @hide */
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        if (mRssi > TDSCDMA_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (mRssi >= TDSCDMA_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
-        else if (mRssi >= TDSCDMA_RSSI_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
-        else if (mRssi >= TDSCDMA_RSSI_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
-        else if (mRssi >= TDSCDMA_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
+        if (mRscp > TDSCDMA_RSCP_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (mRscp >= TDSCDMA_RSCP_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mRscp >= TDSCDMA_RSCP_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mRscp >= TDSCDMA_RSCP_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mRscp >= TDSCDMA_RSCP_POOR) mLevel = SIGNAL_STRENGTH_POOR;
         else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     /**
-     * Get the signal strength as dBm
+     * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     @Override
     public int getDbm() {
@@ -159,6 +157,23 @@
     }
 
     /**
+     * Get the RSSI as dBm value -113..-51dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     *
+     * @hide
+     */
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /**
+     * Get the BER as an ASU value 0..7, 99, or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     * @hide
+     */
+    public int getBitErrorRate() {
+        return mBitErrorRate;
+    }
+
+    /**
      * Get the RSCP in ASU.
      *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index d9fd7f3..1693252 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.StringDef;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -66,7 +67,7 @@
     public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp";
 
     // Default to RSSI for backwards compatibility with older devices
-    private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
+    private static final String DEFAULT_LEVEL_CALCULATION_METHOD = LEVEL_CALCULATION_METHOD_RSSI;
 
     private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown
     private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
@@ -143,13 +144,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
@@ -161,14 +158,14 @@
         int[] rscpThresholds;
 
         if (cc == null) {
-            calcMethod = sLevelCalculationMethod;
+            calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
             rscpThresholds = sRscpThresholds;
         } else {
             // TODO: abstract this entire thing into a series of functions
             calcMethod = cc.getString(
                     CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
-                    sLevelCalculationMethod);
-            if (TextUtils.isEmpty(calcMethod)) calcMethod = sLevelCalculationMethod;
+                    DEFAULT_LEVEL_CALCULATION_METHOD);
+            if (TextUtils.isEmpty(calcMethod)) calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
             rscpThresholds = cc.getIntArray(
                     CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
             if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
@@ -202,7 +199,7 @@
     }
 
     /**
-     * Get the signal strength as dBm
+     * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     @Override
     public int getDbm() {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8c92e84..1a160f4 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -339,6 +339,9 @@
 
     private List<NetworkRegistrationInfo> mNetworkRegistrationInfos = new ArrayList<>();
 
+    private String mOperatorAlphaLongRaw;
+    private String mOperatorAlphaShortRaw;
+
     /**
      * get String description of roaming type
      * @hide
@@ -420,6 +423,8 @@
         mNetworkRegistrationInfos = s.mNetworkRegistrationInfos == null ? null :
                 new ArrayList<>(s.mNetworkRegistrationInfos);
         mNrFrequencyRange = s.mNrFrequencyRange;
+        mOperatorAlphaLongRaw = s.mOperatorAlphaLongRaw;
+        mOperatorAlphaShortRaw = s.mOperatorAlphaShortRaw;
     }
 
     /**
@@ -453,6 +458,8 @@
         mChannelNumber = in.readInt();
         mCellBandwidths = in.createIntArray();
         mNrFrequencyRange = in.readInt();
+        mOperatorAlphaLongRaw = in.readString();
+        mOperatorAlphaShortRaw = in.readString();
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -478,6 +485,8 @@
         out.writeInt(mChannelNumber);
         out.writeIntArray(mCellBandwidths);
         out.writeInt(mNrFrequencyRange);
+        out.writeString(mOperatorAlphaLongRaw);
+        out.writeString(mOperatorAlphaShortRaw);
     }
 
     public int describeContents() {
@@ -836,7 +845,9 @@
                 mIsEmergencyOnly,
                 mLteEarfcnRsrpBoost,
                 mNetworkRegistrationInfos,
-                mNrFrequencyRange);
+                mNrFrequencyRange,
+                mOperatorAlphaLongRaw,
+                mOperatorAlphaShortRaw);
     }
 
     @Override
@@ -862,6 +873,8 @@
                 && equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
                         s.mCdmaDefaultRoamingIndicator)
                 && mIsEmergencyOnly == s.mIsEmergencyOnly
+                && equalsHandlesNulls(mOperatorAlphaLongRaw, s.mOperatorAlphaLongRaw)
+                && equalsHandlesNulls(mOperatorAlphaShortRaw, s.mOperatorAlphaShortRaw)
                 && (mNetworkRegistrationInfos == null
                 ? s.mNetworkRegistrationInfos == null : s.mNetworkRegistrationInfos != null
                 && mNetworkRegistrationInfos.containsAll(s.mNetworkRegistrationInfos))
@@ -1019,6 +1032,8 @@
             .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
             .append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos)
             .append(", mNrFrequencyRange=").append(mNrFrequencyRange)
+            .append(", mOperatorAlphaLongRaw=").append(mOperatorAlphaLongRaw)
+            .append(", mOperatorAlphaShortRaw=").append(mOperatorAlphaShortRaw)
             .append("}").toString();
     }
 
@@ -1056,6 +1071,8 @@
                 .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                 .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
                 .build());
+        mOperatorAlphaLongRaw = null;
+        mOperatorAlphaShortRaw = null;
     }
 
     public void setStateOutOfService() {
@@ -1297,6 +1314,8 @@
         m.putInt("ChannelNumber", mChannelNumber);
         m.putIntArray("CellBandwidths", mCellBandwidths);
         m.putInt("mNrFrequencyRange", mNrFrequencyRange);
+        m.putString("operator-alpha-long-raw", mOperatorAlphaLongRaw);
+        m.putString("operator-alpha-short-raw", mOperatorAlphaShortRaw);
     }
 
     /** @hide */
@@ -1906,4 +1925,36 @@
 
         return state;
     }
+
+    /**
+     * @hide
+     */
+    public void setOperatorAlphaLongRaw(String operatorAlphaLong) {
+        mOperatorAlphaLongRaw = operatorAlphaLong;
+    }
+
+    /**
+     * The current registered raw data network operator name in long alphanumeric format.
+     *
+     * @hide
+     */
+    public String getOperatorAlphaLongRaw() {
+        return mOperatorAlphaLongRaw;
+    }
+
+    /**
+     * @hide
+     */
+    public void setOperatorAlphaShortRaw(String operatorAlphaShort) {
+        mOperatorAlphaShortRaw = operatorAlphaShort;
+    }
+
+    /**
+     * The current registered raw data network operator name in short alphanumeric format.
+     *
+     * @hide
+     */
+    public String getOperatorAlphaShortRaw() {
+        return mOperatorAlphaShortRaw;
+    }
 }
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ee28ca2..cf15b92 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -87,8 +87,8 @@
     private int mCarrierId;
 
     /**
-     * The source of the name, NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
-     * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
+     * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or
+     * NAME_SOURCE_USER_INPUT.
      */
     private int mNameSource;
 
@@ -103,7 +103,7 @@
     private String mNumber;
 
     /**
-     * Data roaming state, DATA_RAOMING_ENABLE, DATA_RAOMING_DISABLE
+     * Data roaming state, DATA_ROAMING_ENABLE, DATA_ROAMING_DISABLE
      */
     private int mDataRoaming;
 
@@ -306,8 +306,8 @@
     }
 
     /**
-     * @return the source of the name, eg NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
-     * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
+     * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or
+     * NAME_SOURCE_USER_INPUT.
      * @hide
      */
     @UnsupportedAppUsage
@@ -316,8 +316,8 @@
     }
 
     /**
-     * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a user
-     * interface.
+     * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a
+     * user interface.
      *
      * @param context A {@code Context} to get the {@code DisplayMetrics}s from.
      *
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a933da7..0c63411 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -364,12 +364,6 @@
     public static final String NAME_SOURCE = "name_source";
 
     /**
-     * The name_source is undefined
-     * @hide
-     */
-    public static final int NAME_SOURCE_UNDEFINDED = -1;
-
-    /**
      * The name_source is the default
      * @hide
      */
@@ -1598,27 +1592,16 @@
     }
 
     /**
-     * Set display name by simInfo index
-     * @param displayName the display name of SIM card
-     * @param subId the unique SubscriptionInfo index in database
-     * @return the number of records updated
-     * @hide
-     */
-    public int setDisplayName(String displayName, int subId) {
-        return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
-    }
-
-    /**
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
      * @param subId the unique SubscriptionInfo index in database
      * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
-     *                   2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
+     *                   2: NAME_SOURCE_USER_INPUT
      * @return the number of records updated or < 0 if invalid subId
      * @hide
      */
     @UnsupportedAppUsage
-    public int setDisplayName(String displayName, int subId, long nameSource) {
+    public int setDisplayName(String displayName, int subId, int nameSource) {
         if (VDBG) {
             logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
                     + " nameSource:" + nameSource);
@@ -2749,6 +2732,8 @@
      *
      * @throws SecurityException if the caller doesn't meet the requirements
      *             outlined above.
+     * @throws IllegalArgumentException if any of the subscriptions in the list doesn't exist.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that will be in the same group
      * @return groupUUID a UUID assigned to the subscription group.
@@ -2797,6 +2782,7 @@
      *             outlined above.
      * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist,
      *             or the groupUuid doesn't exist.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that need adding into the group
      * @param groupUuid the groupUuid the subscriptions are being added to.
@@ -2849,6 +2835,7 @@
      *             outlined above.
      * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong
      *             the specified group.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that need removing from their groups.
      *
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9c63a82..0d3bc1d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3790,6 +3790,7 @@
      * @hide
      * nobody seems to call this.
      */
+    @TestApi
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getLine1AlphaTag() {
         return getLine1AlphaTag(getSubId());
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 7eea218..a86fda4 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -78,10 +78,11 @@
      */
     public static final int TYPE_NONE = ApnTypes.NONE;
     /**
-     * APN type for all APNs.
+     * APN type for all APNs (except wild-cardable types).
      * @hide
      */
-    public static final int TYPE_ALL = ApnTypes.ALL | ApnTypes.MCX;
+    public static final int TYPE_ALL = ApnTypes.DEFAULT | ApnTypes.HIPRI | ApnTypes.MMS
+            | ApnTypes.SUPL | ApnTypes.DUN | ApnTypes.FOTA | ApnTypes.IMS | ApnTypes.CBS;
     /** APN type for default data traffic. */
     public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
     /** APN type for MMS traffic. */
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 01fdae8..cfba052 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -145,21 +145,13 @@
     int setIconTint(int tint, int subId);
 
     /**
-     * Set display name by simInfo index
-     * @param displayName the display name of SIM card
-     * @param subId the unique SubscriptionInfo index in database
-     * @return the number of records updated
-     */
-    int setDisplayName(String displayName, int subId);
-
-    /**
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
      * @param subId the unique SubscriptionInfo index in database
      * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
      * @return the number of records updated
      */
-    int setDisplayNameUsingSrc(String displayName, int subId, long nameSource);
+    int setDisplayNameUsingSrc(String displayName, int subId, int nameSource);
 
     /**
      * Set phone number by subId
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 9d7319f..95b8f67 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -78,6 +78,7 @@
     private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
     private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
     private static final String KEY_CYCLE_CLEAN = "cycle_clean";
+    private static final String KEY_TRACE_ALL = "trace_all";
     private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
     private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
     private static final String KEY_TRACE_DIRECTORY = "trace_directory";
@@ -111,7 +112,7 @@
     private static final String SUCCESS_MESSAGE = "Status: ok";
     private static final String TOTAL_TIME_MESSAGE = "TotalTime:";
     private static final String COMPILE_SUCCESS = "Success";
-    private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
+    private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION-%d";
     private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
     private static final String LAUNCH_ITERATION_PREFIX = "LAUNCH_ITERATION";
     private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
@@ -142,6 +143,7 @@
     private String[] mCompilerFilters = null;
     private String mLastAppName = "";
     private boolean mCycleCleanUp = false;
+    private boolean mTraceAll = false;
     private boolean mIterationCycle = false;
     private long mCycleTime = 0;
     private StringBuilder mCycleTimes = new StringBuilder();
@@ -296,18 +298,40 @@
                         // skip if the app has failures while launched first
                         continue;
                     }
-                    // In the "applaunch.txt" file app launches are referenced using
-                    // "LAUNCH_ITERATION - ITERATION NUM"
-                    launchResults = startApp(launch.getApp(), launch.getLaunchReason());
-                    if (launchResults.mLaunchTime < 0) {
-                        addLaunchResult(launch, new AppLaunchResult());
-                        // if it fails once, skip the rest of the launches
-                        continue;
-                    } else {
-                        mCycleTime += launchResults.mLaunchTime;
-                        addLaunchResult(launch, launchResults);
+                    AtraceLogger atraceLogger = null;
+                    if (mTraceAll) {
+                        Log.i(TAG, "Started tracing " + launch.getApp());
+                        atraceLogger = AtraceLogger
+                                .getAtraceLoggerInstance(getInstrumentation());
                     }
-                    sleep(POST_LAUNCH_IDLE_TIMEOUT);
+                    try {
+                        // Start the trace
+                        if (atraceLogger != null) {
+                            atraceLogger.atraceStart(traceCategoriesSet, traceBufferSize,
+                                    traceDumpInterval, rootTraceSubDir,
+                                    String.format("%s-%s-%s", launch.getApp(),
+                                            launch.getCompilerFilter(), launch.getLaunchReason()));
+                        }
+                        // In the "applaunch.txt" file app launches are referenced using
+                        // "LAUNCH_ITERATION - ITERATION NUM"
+                        launchResults = startApp(launch.getApp(), launch.getLaunchReason());
+                        if (launchResults.mLaunchTime < 0) {
+                            addLaunchResult(launch, new AppLaunchResult());
+                            // if it fails once, skip the rest of the launches
+                            continue;
+                        } else {
+                            mCycleTime += launchResults.mLaunchTime;
+                            addLaunchResult(launch, launchResults);
+                        }
+                        sleep(POST_LAUNCH_IDLE_TIMEOUT);
+                    } finally {
+                        // Stop the trace
+                        if (atraceLogger != null) {
+                            Log.i(TAG, "Stopped tracing " + launch.getApp());
+                            atraceLogger.atraceStop();
+                        }
+                    }
+
                 }
 
                 // App launch times for trace launch will not be used for final
@@ -534,6 +558,7 @@
         mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
         mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
         mCycleCleanUp = Boolean.parseBoolean(args.getString(KEY_CYCLE_CLEAN));
+        mTraceAll = Boolean.parseBoolean(args.getString(KEY_TRACE_ALL));
         mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
 
         if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index b308982..fa7bf61 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static com.android.server.PackageWatchdog.MonitoredPackage;
 import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
 
 import static org.junit.Assert.assertEquals;
@@ -27,6 +28,7 @@
 import android.content.pm.VersionedPackage;
 import android.os.Handler;
 import android.os.test.TestLooper;
+import android.service.watchdog.PackageInfo;
 import android.util.AtomicFile;
 
 import androidx.test.InstrumentationRegistry;
@@ -143,6 +145,31 @@
         assertNull(watchdog.getPackages(observer3));
     }
 
+    /** Observing already observed package extends the observation time. */
+    @Test
+    public void testObserveAlreadyObservedPackage() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer = new TestObserver(OBSERVER_NAME_1);
+
+        // Start observing APP_A
+        watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
+
+        // Then advance time half-way
+        Thread.sleep(SHORT_DURATION / 2);
+        mTestLooper.dispatchAll();
+
+        // Start observing APP_A again
+        watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
+
+        // Then advance time such that it should have expired were it not for the second observation
+        Thread.sleep((SHORT_DURATION / 2) + 1);
+        mTestLooper.dispatchAll();
+
+        // Verify that APP_A not expired since second observation extended the time
+        assertEquals(1, watchdog.getPackages(observer).size());
+        assertTrue(watchdog.getPackages(observer).contains(APP_A));
+    }
+
     /**
      * Test package observers are persisted and loaded on startup
      */
@@ -577,6 +604,84 @@
         assertEquals(APP_C, observer.mFailedPackages.get(0));
     }
 
+    /**
+     * Tests failure when health check duration is different from package observation duration
+     * Failure is also notified only once.
+     */
+    @Test
+    public void testExplicitHealthCheckFailureBeforeExpiry() throws Exception {
+        TestController controller = new TestController();
+        PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
+        TestObserver observer = new TestObserver(OBSERVER_NAME_1,
+                PackageHealthObserverImpact.USER_IMPACT_MEDIUM);
+
+        // Start observing with explicit health checks for APP_A and
+        // package observation duration == LONG_DURATION
+        // health check duration == SHORT_DURATION (set by default in the TestController)
+        controller.setSupportedPackages(Arrays.asList(APP_A));
+        watchdog.startObservingHealth(observer, Arrays.asList(APP_A), LONG_DURATION);
+
+        // Then APP_A has exceeded health check duration
+        Thread.sleep(SHORT_DURATION);
+        mTestLooper.dispatchAll();
+
+        // Verify that health check is failed
+        assertEquals(1, observer.mFailedPackages.size());
+        assertEquals(APP_A, observer.mFailedPackages.get(0));
+
+        // Then clear failed packages and start observing a random package so requests are synced
+        // and PackageWatchdog#onSupportedPackages is called and APP_A has a chance to fail again
+        // this time due to package expiry.
+        observer.mFailedPackages.clear();
+        watchdog.startObservingHealth(observer, Arrays.asList(APP_B), LONG_DURATION);
+
+        // Verify that health check failure is not notified again
+        assertTrue(observer.mFailedPackages.isEmpty());
+    }
+
+    /** Tests {@link MonitoredPackage} health check state transitions. */
+    @Test
+    public void testPackageHealthCheckStateTransitions() {
+        MonitoredPackage m1 = new MonitoredPackage(APP_A, LONG_DURATION,
+                false /* hasPassedHealthCheck */);
+        MonitoredPackage m2 = new MonitoredPackage(APP_B, LONG_DURATION, false);
+        MonitoredPackage m3 = new MonitoredPackage(APP_C, LONG_DURATION, false);
+        MonitoredPackage m4 = new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+
+        // Verify transition: inactive -> active -> passed
+        // Verify initially inactive
+        assertEquals(MonitoredPackage.STATE_INACTIVE, m1.getHealthCheckStateLocked());
+        // Verify still inactive, until we #setHealthCheckActiveLocked
+        assertEquals(MonitoredPackage.STATE_INACTIVE, m1.handleElapsedTimeLocked(SHORT_DURATION));
+        // Verify now active
+        assertEquals(MonitoredPackage.STATE_ACTIVE, m1.setHealthCheckActiveLocked(SHORT_DURATION));
+        // Verify now passed
+        assertEquals(MonitoredPackage.STATE_PASSED, m1.tryPassHealthCheckLocked());
+
+        // Verify transition: inactive -> active -> failed
+        // Verify initially inactive
+        assertEquals(MonitoredPackage.STATE_INACTIVE, m2.getHealthCheckStateLocked());
+        // Verify now active
+        assertEquals(MonitoredPackage.STATE_ACTIVE, m2.setHealthCheckActiveLocked(SHORT_DURATION));
+        // Verify now failed
+        assertEquals(MonitoredPackage.STATE_FAILED, m2.handleElapsedTimeLocked(SHORT_DURATION));
+
+        // Verify transition: inactive -> failed
+        // Verify initially inactive
+        assertEquals(MonitoredPackage.STATE_INACTIVE, m3.getHealthCheckStateLocked());
+        // Verify now failed because package expired
+        assertEquals(MonitoredPackage.STATE_FAILED, m3.handleElapsedTimeLocked(LONG_DURATION));
+        // Verify remains failed even when asked to pass
+        assertEquals(MonitoredPackage.STATE_FAILED, m3.tryPassHealthCheckLocked());
+
+        // Verify transition: passed
+        assertEquals(MonitoredPackage.STATE_PASSED, m4.getHealthCheckStateLocked());
+        // Verify remains passed even if health check fails
+        assertEquals(MonitoredPackage.STATE_PASSED, m4.handleElapsedTimeLocked(SHORT_DURATION));
+        // Verify remains passed even if package expires
+        assertEquals(MonitoredPackage.STATE_PASSED, m4.handleElapsedTimeLocked(LONG_DURATION));
+    }
+
     private PackageWatchdog createWatchdog() {
         return createWatchdog(new TestController(), true /* withPackagesReady */);
     }
@@ -636,7 +741,7 @@
         private List<String> mSupportedPackages = new ArrayList<>();
         private List<String> mRequestedPackages = new ArrayList<>();
         private Consumer<String> mPassedConsumer;
-        private Consumer<List<String>> mSupportedConsumer;
+        private Consumer<List<PackageInfo>> mSupportedConsumer;
         private Runnable mNotifySyncRunnable;
 
         @Override
@@ -649,7 +754,7 @@
 
         @Override
         public void setCallbacks(Consumer<String> passedConsumer,
-                Consumer<List<String>> supportedConsumer, Runnable notifySyncRunnable) {
+                Consumer<List<PackageInfo>> supportedConsumer, Runnable notifySyncRunnable) {
             mPassedConsumer = passedConsumer;
             mSupportedConsumer = supportedConsumer;
             mNotifySyncRunnable = notifySyncRunnable;
@@ -661,7 +766,11 @@
             if (mIsEnabled) {
                 packages.retainAll(mSupportedPackages);
                 mRequestedPackages.addAll(packages);
-                mSupportedConsumer.accept(mSupportedPackages);
+                List<PackageInfo> packageInfos = new ArrayList<>();
+                for (String packageName: packages) {
+                    packageInfos.add(new PackageInfo(packageName, SHORT_DURATION));
+                }
+                mSupportedConsumer.accept(packageInfos);
             } else {
                 mSupportedConsumer.accept(Collections.emptyList());
             }
diff --git a/tests/ProtoInputStreamTests/Android.mk b/tests/ProtoInputStreamTests/Android.mk
new file mode 100644
index 0000000..eb747cc
--- /dev/null
+++ b/tests/ProtoInputStreamTests/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)
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := ProtoInputStreamTests
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_MODULE_TAGS := tests optional
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-proto-files-under, src)
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_CERTIFICATE := platform
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    androidx.test.rules \
+    frameworks-base-testutils \
+    mockito-target-minus-junit4
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/ProtoInputStreamTests/AndroidManifest.xml b/tests/ProtoInputStreamTests/AndroidManifest.xml
new file mode 100644
index 0000000..c11aa73
--- /dev/null
+++ b/tests/ProtoInputStreamTests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.test.protoinputstream">
+    <application>
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.test.protoinputstream"
+                     android:label="ProtoInputStream Tests">
+    </instrumentation>
+</manifest>
\ No newline at end of file
diff --git a/tests/ProtoInputStreamTests/AndroidTest.xml b/tests/ProtoInputStreamTests/AndroidTest.xml
new file mode 100644
index 0000000..51ab88e
--- /dev/null
+++ b/tests/ProtoInputStreamTests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for ProtoInputStream Tests">
+    <option name="test-suite-tag" value="ProtoInputStreamTests" />
+    <option name="config-descriptor:metadata" key="component" value="metrics" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="ProtoInputStreamTests.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.test.protoinputstream" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/tests/ProtoInputStreamTests/TEST_MAPPING b/tests/ProtoInputStreamTests/TEST_MAPPING
new file mode 100644
index 0000000..cf9f077
--- /dev/null
+++ b/tests/ProtoInputStreamTests/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "ProtoInputStreamTests"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBoolTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBoolTest.java
new file mode 100644
index 0000000..c21c403
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBoolTest.java
@@ -0,0 +1,500 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamBoolTest extends TestCase {
+
+    /**
+     * Test reading single bool field
+     */
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    /**
+     * Implementation of testRead with a given chunkSize.
+     */
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 3 -> 1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        boolean[] results = new boolean[2];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readBoolean(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(false, results[0]);
+        assertEquals(true, results[1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(false);
+        testReadCompat(true);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(boolean val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+        final long fieldId = fieldFlags | ((long) 130 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.boolField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        boolean result = false; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readBoolean(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.boolField, result);
+    }
+
+
+    /**
+     * Test reading repeated bool field
+     */
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+
+                // 4 -> 0
+                (byte) 0x20,
+                (byte) 0x00,
+                // 4 -> 1
+                (byte) 0x20,
+                (byte) 0x01,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+
+                // 3 -> 0
+                (byte) 0x18,
+                (byte) 0x00,
+                // 3 -> 1
+                (byte) 0x18,
+                (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        boolean[][] results = new boolean[3][2];
+        int[] indices = new int[3];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readBoolean(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readBoolean(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readBoolean(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(false, results[0][0]);
+        assertEquals(false, results[0][1]);
+        assertEquals(true, results[1][0]);
+        assertEquals(true, results[1][1]);
+        assertEquals(false, results[2][0]);
+        assertEquals(true, results[2][1]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new boolean[0]);
+        testRepeatedCompat(new boolean[]{false, true});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(boolean[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BOOL;
+        final long fieldId = fieldFlags | ((long) 131 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.boolFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        boolean[] result = new boolean[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readBoolean(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.boolFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.boolFieldRepeated[i], result[i]);
+        }
+    }
+
+    /**
+     * Test reading packed bool field
+     */
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws IOException {
+
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 4 -> 0,1
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x01,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 3 -> 0,1
+                (byte) 0x1a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x01,
+        };
+
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        boolean[][] results = new boolean[3][2];
+        int[] indices = new int[3];
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readBoolean(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readBoolean(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readBoolean(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(false, results[0][0]);
+        assertEquals(false, results[0][1]);
+        assertEquals(true, results[1][0]);
+        assertEquals(true, results[1][1]);
+        assertEquals(false, results[2][0]);
+        assertEquals(true, results[2][1]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new boolean[0]);
+        testPackedCompat(new boolean[]{false, true});
+    }
+
+    /**
+     * Implementation of testPackedCompat with a given value.
+     */
+    private void testPackedCompat(boolean[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_BOOL;
+        final long fieldId = fieldFlags | ((long) 132 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.boolFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        boolean[] result = new boolean[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readBoolean(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.boolFieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.boolFieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readBoolean(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readBoolean(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readBoolean(fieldId3);
+                        // don't fail, length delimited is ok (represents packed booleans)
+                        break;
+                    case (int) fieldId6:
+                        pi.readBoolean(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBytesTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBytesTest.java
new file mode 100644
index 0000000..09fe40e
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBytesTest.java
@@ -0,0 +1,423 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+public class ProtoInputStreamBytesTest extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 5 -> { 0, 1, 2, 3, 4 }
+                (byte) 0x2a,
+                (byte) 0x05,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte) 0x1a,
+                (byte) 0x06,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte) 0x22,
+                (byte) 0x04,
+                (byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        byte[][] results = new byte[4][];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0] = pi.readBytes(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readBytes(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readBytes(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readBytes(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertTrue("Expected: []  Actual: " + Arrays.toString(results[0]),
+                Arrays.equals(new byte[]{}, results[0]));
+        assertTrue("Expected: []  Actual: " + Arrays.toString(results[1]),
+                Arrays.equals(new byte[]{}, results[1]));
+        assertTrue("Expected: [0, 1, 2, 3, 4, 5]  Actual: " + Arrays.toString(results[2]),
+                Arrays.equals(new byte[]{0, 1, 2, 3, 4, 5}, results[2]));
+        assertTrue("Expected: [-1, -2, -3, -4]  Actual: " + Arrays.toString(results[3]),
+                Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
+                        results[3]));
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(new byte[0]);
+        testReadCompat(new byte[]{1, 2, 3, 4});
+        testReadCompat(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc});
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(byte[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+        final long fieldId = fieldFlags | ((long) 150 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.bytesField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        byte[] result = new byte[val.length];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readBytes(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.bytesField.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.bytesField[i], result[i]);
+        }
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte) 0x1a,
+                (byte) 0x06,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte) 0x22,
+                (byte) 0x04,
+                (byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
+
+                // 5 -> { 0, 1, 2, 3, 4}
+                (byte) 0x2a,
+                (byte) 0x05,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte) 0x1a,
+                (byte) 0x06,
+                (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte) 0x22,
+                (byte) 0x04,
+                (byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        byte[][][] results = new byte[4][2][];
+        int[] indices = new int[4];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readBytes(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readBytes(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readBytes(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readBytes(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assert (Arrays.equals(new byte[]{}, results[0][0]));
+        assert (Arrays.equals(new byte[]{}, results[0][1]));
+        assert (Arrays.equals(new byte[]{}, results[1][0]));
+        assert (Arrays.equals(new byte[]{}, results[1][1]));
+        assert (Arrays.equals(new byte[]{1, 2, 3, 4}, results[2][0]));
+        assert (Arrays.equals(new byte[]{1, 2, 3, 4}, results[2][1]));
+        assert (Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
+                results[3][0]));
+        assert (Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
+                results[3][1]));
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new byte[0][]);
+        testRepeatedCompat(new byte[][]{
+                new byte[0],
+                new byte[]{1, 2, 3, 4},
+                new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc}
+        });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(byte[][] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BYTES;
+        final long fieldId = fieldFlags | ((long) 151 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.bytesFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        byte[][] result = new byte[val.length][]; // start off with default value
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readBytes(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.bytesFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.bytesFieldRepeated[i].length, result[i].length);
+            for (int j = 0; j < result[i].length; j++) {
+                assertEquals(readback.bytesFieldRepeated[i][j], result[i][j]);
+            }
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> {1}
+                (byte) 0x0a,
+                (byte) 0x01,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readBytes(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readBytes(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readBytes(fieldId3);
+                        // don't fail, length delimited is ok
+                        break;
+                    case (int) fieldId6:
+                        pi.readBytes(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamDoubleTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamDoubleTest.java
new file mode 100644
index 0000000..118fe34
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamDoubleTest.java
@@ -0,0 +1,728 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamDoubleTest extends TestCase {
+
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x51,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x19,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x21,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x29,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x39,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x41,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x49,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        double[] results = new double[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readDouble(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readDouble(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readDouble(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readDouble(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5] = pi.readDouble(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6] = pi.readDouble(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    results[7] = pi.readDouble(fieldId8);
+                    break;
+                case (int) fieldId9:
+                    results[8] = pi.readDouble(fieldId9);
+                    break;
+                case (int) fieldId10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0, results[0]);
+        assertEquals(1.0, results[1]);
+        assertEquals(-1234.432, results[2]);
+        assertEquals(42.42, results[3]);
+        assertEquals(Double.MIN_NORMAL, results[4]);
+        assertEquals(Double.MIN_VALUE, results[5]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6]);
+        assertEquals(Double.NaN, results[7]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1234.432);
+        testReadCompat(42.42);
+        testReadCompat(Double.MIN_NORMAL);
+        testReadCompat(Double.MIN_VALUE);
+        testReadCompat(Double.NEGATIVE_INFINITY);
+        testReadCompat(Double.NaN);
+        testReadCompat(Double.POSITIVE_INFINITY);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(double val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+        final long fieldId = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.doubleField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        double result = 0.0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readDouble(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.doubleField, result);
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x19,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x21,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x29,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x39,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x41,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x49,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+                // 10 -> 1
+                (byte) 0x51,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x19,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x21,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x29,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x39,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x41,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x49,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        double[][] results = new double[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readDouble(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readDouble(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readDouble(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readDouble(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readDouble(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readDouble(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readDouble(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    results[7][indices[7]++] = pi.readDouble(fieldId8);
+                    break;
+                case (int) fieldId9:
+                    results[8][indices[8]++] = pi.readDouble(fieldId9);
+                    break;
+                case (int) fieldId10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0, results[0][0]);
+        assertEquals(0.0, results[0][1]);
+        assertEquals(1.0, results[1][0]);
+        assertEquals(1.0, results[1][1]);
+        assertEquals(-1234.432, results[2][0]);
+        assertEquals(-1234.432, results[2][1]);
+        assertEquals(42.42, results[3][0]);
+        assertEquals(42.42, results[3][1]);
+        assertEquals(Double.MIN_NORMAL, results[4][0]);
+        assertEquals(Double.MIN_NORMAL, results[4][1]);
+        assertEquals(Double.MIN_VALUE, results[5][0]);
+        assertEquals(Double.MIN_VALUE, results[5][1]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Double.NaN, results[7][0]);
+        assertEquals(Double.NaN, results[7][1]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new double[0]);
+        testRepeatedCompat(new double[]{0, 1, -1234.432, 42.42,
+                Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
+                Double.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(double[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
+        final long fieldId = fieldFlags | ((long) 11 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.doubleFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        double[] result = new double[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readDouble(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.doubleFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.doubleFieldRepeated[i], result[i]);
+        }
+    }
+
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x52,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1a,
+                (byte) 0x10,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
+                (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
+                // 4 -> 42.42
+                (byte) 0x22,
+                (byte) 0x10,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
+                (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte) 0x2a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte) 0x3a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
+                // 8 -> Double.NaN
+                (byte) 0x42,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte) 0x4a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        double[][] results = new double[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readDouble(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readDouble(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readDouble(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readDouble(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readDouble(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readDouble(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readDouble(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    results[7][indices[7]++] = pi.readDouble(fieldId8);
+                    break;
+                case (int) fieldId9:
+                    results[8][indices[8]++] = pi.readDouble(fieldId9);
+                    break;
+                case (int) fieldId10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0, results[0][0]);
+        assertEquals(0.0, results[0][1]);
+        assertEquals(1.0, results[1][0]);
+        assertEquals(1.0, results[1][1]);
+        assertEquals(-1234.432, results[2][0]);
+        assertEquals(-1234.432, results[2][1]);
+        assertEquals(42.42, results[3][0]);
+        assertEquals(42.42, results[3][1]);
+        assertEquals(Double.MIN_NORMAL, results[4][0]);
+        assertEquals(Double.MIN_NORMAL, results[4][1]);
+        assertEquals(Double.MIN_VALUE, results[5][0]);
+        assertEquals(Double.MIN_VALUE, results[5][1]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Double.NaN, results[7][0]);
+        assertEquals(Double.NaN, results[7][1]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new double[0]);
+        testPackedCompat(new double[]{0, 1, -1234.432, 42.42,
+                Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
+                Double.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testPackedCompat with a given value.
+     */
+    private void testPackedCompat(double[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
+        final long fieldId = fieldFlags | ((long) 12 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.doubleFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        double[] result = new double[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readDouble(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.doubleFieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.doubleFieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x09,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readDouble(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readDouble(fieldId2);
+                        // don't fail, fixed64 is ok
+                        break;
+                    case (int) fieldId3:
+                        pi.readDouble(fieldId3);
+                        // don't fail, length delimited is ok (represents packed doubles)
+                        break;
+                    case (int) fieldId6:
+                        pi.readDouble(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamEnumTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamEnumTest.java
new file mode 100644
index 0000000..f55d951
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamEnumTest.java
@@ -0,0 +1,570 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamEnumTest extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+        final long fieldId = fieldFlags | ((long) 160 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.outsideField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        // Nano proto drops values that are outside the range, so compare against val
+        assertEquals(val, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[]{});
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_ENUM;
+        final long fieldId = fieldFlags | ((long) 161 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.outsideFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        // Nano proto drops values that are outside the range, so compare against val
+        assertEquals(val.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(val[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[]{});
+        testPackedCompat(new int[]{0, 1});
+
+        // Nano proto has a bug.  It gets the size with computeInt32SizeNoTag (correctly)
+        // but incorrectly uses writeRawVarint32 to write the value for negative numbers.
+        //testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_ENUM;
+        final long fieldId = fieldFlags | ((long) 162 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.outsideFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        // Nano proto drops values that are outside the range, so compare against val
+        assertEquals(val.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(val[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readInt(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readInt(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readInt(fieldId3);
+                        // don't fail, length delimited is ok (represents packed enums)
+                        break;
+                    case (int) fieldId6:
+                        pi.readInt(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed32Test.java
new file mode 100644
index 0000000..df68476
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed32Test.java
@@ -0,0 +1,547 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamFixed32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+        final long fieldId = fieldFlags | ((long) 90 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
+        final long fieldId = fieldFlags | ((long) 91 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x32,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
+        final long fieldId = fieldFlags | ((long) 92 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x0d,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x04,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readInt(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readInt(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readInt(fieldId3);
+                        // don't fail, length delimited is ok (represents packed fixed32)
+                        break;
+                    case (int) fieldId6:
+                        pi.readInt(fieldId6);
+                        // don't fail, fixed32 is ok
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed64Test.java
new file mode 100644
index 0000000..af4130b
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed64Test.java
@@ -0,0 +1,649 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamFixed64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+        final long fieldId = fieldFlags | ((long) 100 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
+        final long fieldId = fieldFlags | ((long) 101 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 8 -> 1
+                (byte) 0x42,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
+        final long fieldId = fieldFlags | ((long) 102 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.fixed64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.fixed64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.fixed64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x09,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readLong(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readLong(fieldId2);
+                        // don't fail, fixed64 is ok
+                        break;
+                    case (int) fieldId3:
+                        pi.readLong(fieldId3);
+                        // don't fail, length delimited is ok (represents packed fixed64)
+                        break;
+                    case (int) fieldId6:
+                        pi.readLong(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFloatTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFloatTest.java
new file mode 100644
index 0000000..9bc07dc
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFloatTest.java
@@ -0,0 +1,679 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamFloatTest extends TestCase {
+
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x55,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1d,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x25,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x45,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        float[] results = new float[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readFloat(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readFloat(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readFloat(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readFloat(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5] = pi.readFloat(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6] = pi.readFloat(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    results[7] = pi.readFloat(fieldId8);
+                    break;
+                case (int) fieldId9:
+                    results[8] = pi.readFloat(fieldId9);
+                    break;
+                case (int) fieldId10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0f, results[0]);
+        assertEquals(1.0f, results[1]);
+        assertEquals(-1234.432f, results[2]);
+        assertEquals(42.42f, results[3]);
+        assertEquals(Float.MIN_NORMAL, results[4]);
+        assertEquals(Float.MIN_VALUE, results[5]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6]);
+        assertEquals(Float.NaN, results[7]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1234.432f);
+        testReadCompat(42.42f);
+        testReadCompat(Float.MIN_NORMAL);
+        testReadCompat(Float.MIN_VALUE);
+        testReadCompat(Float.NEGATIVE_INFINITY);
+        testReadCompat(Float.NaN);
+        testReadCompat(Float.POSITIVE_INFINITY);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(float val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+        final long fieldId = fieldFlags | ((long) 20 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.floatField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        float result = 0.0f; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readFloat(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.floatField, result);
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1d,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x25,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x45,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+
+                // 10 -> 1
+                (byte) 0x55,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1d,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x25,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x45,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        float[][] results = new float[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readFloat(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readFloat(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readFloat(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readFloat(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readFloat(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readFloat(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readFloat(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    results[7][indices[7]++] = pi.readFloat(fieldId8);
+                    break;
+                case (int) fieldId9:
+                    results[8][indices[8]++] = pi.readFloat(fieldId9);
+                    break;
+                case (int) fieldId10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0f, results[0][0]);
+        assertEquals(0.0f, results[0][1]);
+        assertEquals(1.0f, results[1][0]);
+        assertEquals(1.0f, results[1][1]);
+        assertEquals(-1234.432f, results[2][0]);
+        assertEquals(-1234.432f, results[2][1]);
+        assertEquals(42.42f, results[3][0]);
+        assertEquals(42.42f, results[3][1]);
+        assertEquals(Float.MIN_NORMAL, results[4][0]);
+        assertEquals(Float.MIN_NORMAL, results[4][1]);
+        assertEquals(Float.MIN_VALUE, results[5][0]);
+        assertEquals(Float.MIN_VALUE, results[5][1]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Float.NaN, results[7][0]);
+        assertEquals(Float.NaN, results[7][1]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new float[0]);
+        testRepeatedCompat(new float[]{0, 1, -1234.432f, 42.42f,
+                Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
+                Float.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(float[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FLOAT;
+        final long fieldId = fieldFlags | ((long) 21 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.floatFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        float[] result = new float[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readFloat(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.floatFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.floatFieldRepeated[i], result[i]);
+        }
+    }
+
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+        final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
+        final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 10 -> 1
+                (byte) 0x52,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
+                // 3 -> -1234.432
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                (byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
+                // 4 -> 42.42
+                (byte) 0x22,
+                (byte) 0x08,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                (byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte) 0x2a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte) 0x3a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
+                // 8 -> Float.NaN
+                (byte) 0x42,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte) 0x4a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        float[][] results = new float[9][2];
+        int[] indices = new int[9];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readFloat(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readFloat(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readFloat(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readFloat(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readFloat(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readFloat(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readFloat(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    results[7][indices[7]++] = pi.readFloat(fieldId8);
+                    break;
+                case (int) fieldId9:
+                    results[8][indices[8]++] = pi.readFloat(fieldId9);
+                    break;
+                case (int) fieldId10:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+        assertEquals(0.0f, results[0][0]);
+        assertEquals(0.0f, results[0][1]);
+        assertEquals(1.0f, results[1][0]);
+        assertEquals(1.0f, results[1][1]);
+        assertEquals(-1234.432f, results[2][0]);
+        assertEquals(-1234.432f, results[2][1]);
+        assertEquals(42.42f, results[3][0]);
+        assertEquals(42.42f, results[3][1]);
+        assertEquals(Float.MIN_NORMAL, results[4][0]);
+        assertEquals(Float.MIN_NORMAL, results[4][1]);
+        assertEquals(Float.MIN_VALUE, results[5][0]);
+        assertEquals(Float.MIN_VALUE, results[5][1]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][0]);
+        assertEquals(Float.NEGATIVE_INFINITY, results[6][1]);
+        assertEquals(Float.NaN, results[7][0]);
+        assertEquals(Float.NaN, results[7][1]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][0]);
+        assertEquals(Float.POSITIVE_INFINITY, results[8][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new float[0]);
+        testPackedCompat(new float[]{0, 1, -1234.432f, 42.42f,
+                Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
+                Float.POSITIVE_INFINITY,
+        });
+    }
+
+    /**
+     * Implementation of testPackedCompat with a given value.
+     */
+    private void testPackedCompat(float[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FLOAT;
+        final long fieldId = fieldFlags | ((long) 22 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.floatFieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        float[] result = new float[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readFloat(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.floatFieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.floatFieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x0d,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x04,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readFloat(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readFloat(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readFloat(fieldId3);
+                        // don't fail, length delimited is ok (represents packed floats)
+                        break;
+                    case (int) fieldId6:
+                        pi.readFloat(fieldId6);
+                        // don't fail, fixed32 is ok
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt32Test.java
new file mode 100644
index 0000000..0065870
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt32Test.java
@@ -0,0 +1,565 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamInt32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+        final long fieldId = fieldFlags | ((long) 30 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
+        final long fieldId = fieldFlags | ((long) 31 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_INT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
+        final long fieldId = fieldFlags | ((long) 32 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readInt(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readInt(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readInt(fieldId3);
+                        // don't fail, length delimited is ok (represents packed int32)
+                        break;
+                    case (int) fieldId6:
+                        pi.readInt(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt64Test.java
new file mode 100644
index 0000000..4d6d105
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt64Test.java
@@ -0,0 +1,645 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamInt64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 8 -> Long.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+        final long fieldId = fieldFlags | ((long) 40 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> Long.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
+        final long fieldId = fieldFlags | ((long) 41 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_INT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 8 -> Long.MAX_VALUE
+                (byte) 0x42,
+                (byte) 0x12,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x12,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
+        final long fieldId = fieldFlags | ((long) 42 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.int64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.int64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.int64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readLong(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readLong(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readLong(fieldId3);
+                        // don't fail, length delimited is ok (represents packed int64)
+                        break;
+                    case (int) fieldId6:
+                        pi.readLong(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamObjectTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamObjectTest.java
new file mode 100644
index 0000000..5e49eea
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamObjectTest.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamObjectTest extends TestCase {
+
+
+    class SimpleObject {
+        public char mChar;
+        public char mLargeChar;
+        public String mString;
+        public SimpleObject mNested;
+
+        void parseProto(ProtoInputStream pi) throws IOException {
+            final long uintFieldFlags =
+                    ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+            final long stringFieldFlags =
+                    ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+            final long messageFieldFlags =
+                    ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+            final long charId = uintFieldFlags | ((long) 2 & 0x0ffffffffL);
+            final long largeCharId = uintFieldFlags | ((long) 5000 & 0x0ffffffffL);
+            final long stringId = stringFieldFlags | ((long) 4 & 0x0ffffffffL);
+            final long nestedId = messageFieldFlags | ((long) 5 & 0x0ffffffffL);
+
+            while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                switch (pi.getFieldNumber()) {
+                    case (int) charId:
+                        mChar = (char) pi.readInt(charId);
+                        break;
+                    case (int) largeCharId:
+                        mLargeChar = (char) pi.readInt(largeCharId);
+                        break;
+                    case (int) stringId:
+                        mString = pi.readString(stringId);
+                        break;
+                    case (int) nestedId:
+                        long token = pi.start(nestedId);
+                        mNested = new SimpleObject();
+                        mNested.parseProto(pi);
+                        pi.end(token);
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Test reading an object with one char in it.
+     */
+    public void testObjectOneChar() throws IOException {
+        testObjectOneChar(0);
+        testObjectOneChar(1);
+        testObjectOneChar(5);
+    }
+
+    /**
+     * Implementation of testObjectOneChar for a given chunkSize.
+     */
+    private void testObjectOneChar(int chunkSize) throws IOException {
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long messageId1 = messageFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // Message 2 : { char 2 : 'c' }
+                (byte) 0x12, (byte) 0x02, (byte) 0x10, (byte) 0x63,
+                // Message 1 : { char 2 : 'b' }
+                (byte) 0x0a, (byte) 0x02, (byte) 0x10, (byte) 0x62,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject result = null;
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) messageId1:
+                    final long token = pi.start(messageId1);
+                    result = new SimpleObject();
+                    result.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) messageId2:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNotNull(result);
+        assertEquals('b', result.mChar);
+    }
+
+    /**
+     * Test reading an object with one multibyte unicode char in it.
+     */
+    public void testObjectOneLargeChar() throws IOException {
+        testObjectOneLargeChar(0);
+        testObjectOneLargeChar(1);
+        testObjectOneLargeChar(5);
+    }
+
+    /**
+     * Implementation of testObjectOneLargeChar for a given chunkSize.
+     */
+    private void testObjectOneLargeChar(int chunkSize) throws IOException {
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long messageId1 = messageFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // Message 2 : { char 5000 : '\u3110' }
+                (byte) 0x12, (byte) 0x05, (byte) 0xc0, (byte) 0xb8,
+                (byte) 0x02, (byte) 0x90, (byte) 0x62,
+                // Message 1 : { char 5000 : '\u3110' }
+                (byte) 0x0a, (byte) 0x05, (byte) 0xc0, (byte) 0xb8,
+                (byte) 0x02, (byte) 0x90, (byte) 0x62,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject result = null;
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) messageId1:
+                    final long token = pi.start(messageId1);
+                    result = new SimpleObject();
+                    result.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) messageId2:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNotNull(result);
+        assertEquals('\u3110', result.mLargeChar);
+    }
+
+    /**
+     * Test reading a char, then an object, then a char.
+     */
+    public void testObjectAndTwoChars() throws IOException {
+        testObjectAndTwoChars(0);
+        testObjectAndTwoChars(1);
+        testObjectAndTwoChars(5);
+    }
+
+    /**
+     * Implementation of testObjectAndTwoChars for a given chunkSize.
+     */
+    private void testObjectAndTwoChars(int chunkSize) throws IOException  {
+        final long uintFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long charId1 = uintFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long charId4 = uintFieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 'a'
+                (byte) 0x08, (byte) 0x61,
+                // Message 1 : { char 2 : 'b' }
+                (byte) 0x12, (byte) 0x02, (byte) 0x10, (byte) 0x62,
+                // 4 -> 'c'
+                (byte) 0x20, (byte) 0x63,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject obj = null;
+        char char1 = '\0';
+        char char4 = '\0';
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) charId1:
+                    char1 = (char) pi.readInt(charId1);
+                    break;
+                case (int) messageId2:
+                    final long token = pi.start(messageId2);
+                    obj = new SimpleObject();
+                    obj.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) charId4:
+                    char4 = (char) pi.readInt(charId4);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals('a', char1);
+        assertNotNull(obj);
+        assertEquals('b', obj.mChar);
+        assertEquals('c', char4);
+    }
+
+    /**
+     * Test reading a char, then an object with an int and a string in it, then a char.
+     */
+    public void testComplexObject() throws IOException {
+        testComplexObject(0);
+        testComplexObject(1);
+        testComplexObject(5);
+    }
+
+    /**
+     * Implementation of testComplexObject for a given chunkSize.
+     */
+    private void testComplexObject(int chunkSize) throws IOException  {
+        final long uintFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long charId1 = uintFieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long charId4 = uintFieldFlags | ((long) 4 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 'x'
+                (byte) 0x08, (byte) 0x78,
+                // begin object 2
+                (byte) 0x12, (byte) 0x10,
+                // 2 -> 'y'
+                (byte) 0x10, (byte) 0x79,
+                // 4 -> "abcdefghijkl"
+                (byte) 0x22, (byte) 0x0c,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66,
+                (byte) 0x67, (byte) 0x68, (byte) 0x69, (byte) 0x6a, (byte) 0x6b, (byte) 0x6c,
+                // 4 -> 'z'
+                (byte) 0x20, (byte) 0x7a,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject obj = null;
+        char char1 = '\0';
+        char char4 = '\0';
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) charId1:
+                    char1 = (char) pi.readInt(charId1);
+                    break;
+                case (int) messageId2:
+                    final long token = pi.start(messageId2);
+                    obj = new SimpleObject();
+                    obj.parseProto(pi);
+                    pi.end(token);
+                    break;
+                case (int) charId4:
+                    char4 = (char) pi.readInt(charId4);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals('x', char1);
+        assertNotNull(obj);
+        assertEquals('y', obj.mChar);
+        assertEquals("abcdefghijkl", obj.mString);
+        assertEquals('z', char4);
+    }
+
+    /**
+     * Test reading 3 levels deep of objects.
+     */
+    public void testDeepObjects() throws IOException {
+        testDeepObjects(0);
+        testDeepObjects(1);
+        testDeepObjects(5);
+    }
+
+    /**
+     * Implementation of testDeepObjects for a given chunkSize.
+     */
+    private void testDeepObjects(int chunkSize) throws IOException  {
+        final long messageFieldFlags =
+                ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+        final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // begin object id 2
+                (byte) 0x12, (byte) 0x1a,
+                // 2 -> 'a'
+                (byte) 0x10, (byte) 0x61,
+                // begin nested object id 5
+                (byte) 0x2a, (byte) 0x15,
+                // 5000 -> '\u3110'
+                (byte) 0xc0, (byte) 0xb8,
+                (byte) 0x02, (byte) 0x90, (byte) 0x62,
+                // begin nested object id 5
+                (byte) 0x2a, (byte) 0x0e,
+                // 4 -> "abcdefghijkl"
+                (byte) 0x22, (byte) 0x0c,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66,
+                (byte) 0x67, (byte) 0x68, (byte) 0x69, (byte) 0x6a, (byte) 0x6b, (byte) 0x6c,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+
+        SimpleObject obj = null;
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) messageId2:
+                    final long token = pi.start(messageId2);
+                    obj = new SimpleObject();
+                    obj.parseProto(pi);
+                    pi.end(token);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNotNull(obj);
+        assertEquals('a', obj.mChar);
+        assertNotNull(obj.mNested);
+        assertEquals('\u3110', obj.mNested.mLargeChar);
+        assertNotNull(obj.mNested.mNested);
+        assertEquals("abcdefghijkl", obj.mNested.mNested.mString);
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> {1}
+                (byte) 0x0a,
+                (byte) 0x01,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readBytes(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readBytes(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readBytes(fieldId3);
+                        // don't fail, length delimited is ok
+                        break;
+                    case (int) fieldId6:
+                        pi.readBytes(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed32Test.java
new file mode 100644
index 0000000..75c88a4
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed32Test.java
@@ -0,0 +1,547 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSFixed32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+        final long fieldId = fieldFlags | ((long) 110 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 6 -> 1
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0d,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x15,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x25,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2d,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
+        final long fieldId = fieldFlags | ((long) 111 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> 1
+                (byte) 0x32,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x08,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x08,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
+        final long fieldId = fieldFlags | ((long) 112 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x04,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readInt(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readInt(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readInt(fieldId3);
+                        // don't fail, length delimited is ok (represents packed sfixed32)
+                        break;
+                    case (int) fieldId6:
+                        pi.readInt(fieldId6);
+                        // don't fail, fixed32 is ok
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed64Test.java
new file mode 100644
index 0000000..4c65cf4
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed64Test.java
@@ -0,0 +1,648 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSFixed64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 8 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+        final long fieldId = fieldFlags | ((long) 120 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> 1
+                (byte) 0x41,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x09,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x19,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x21,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x29,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x31,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x39,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
+        final long fieldId = fieldFlags | ((long) 121 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 8 -> 1
+                (byte) 0x42,
+                (byte) 0x10,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x10,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
+        final long fieldId = fieldFlags | ((long) 122 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sfixed64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sfixed64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sfixed64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readLong(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readLong(fieldId2);
+                        // don't fail, fixed32 is ok
+                        break;
+                    case (int) fieldId3:
+                        pi.readLong(fieldId3);
+                        // don't fail, length delimited is ok (represents packed sfixed64)
+                        break;
+                    case (int) fieldId6:
+                        pi.readLong(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt32Test.java
new file mode 100644
index 0000000..6854cd8
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt32Test.java
@@ -0,0 +1,547 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSInt32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+        final long fieldId = fieldFlags | ((long) 70 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
+        final long fieldId = fieldFlags | ((long) 71 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x02,
+                (byte) 0x02,
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
+        final long fieldId = fieldFlags | ((long) 72 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readInt(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readInt(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readInt(fieldId3);
+                        // don't fail, length delimited is ok (represents packed sint32)
+                        break;
+                    case (int) fieldId6:
+                        pi.readInt(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt64Test.java
new file mode 100644
index 0000000..c53e9d7
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt64Test.java
@@ -0,0 +1,622 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamSInt64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+        final long fieldId = fieldFlags | ((long) 80 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x02,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
+        final long fieldId = fieldFlags | ((long) 81 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x02,
+                (byte) 0x02,
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x42,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x14,
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
+        final long fieldId = fieldFlags | ((long) 82 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.sint64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.sint64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.sint64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readLong(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readLong(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readLong(fieldId3);
+                        // don't fail, length delimited is ok (represents packed sint64)
+                        break;
+                    case (int) fieldId6:
+                        pi.readLong(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamStringTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamStringTest.java
new file mode 100644
index 0000000..816d5f9
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamStringTest.java
@@ -0,0 +1,404 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamStringTest extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, not written
+                // 2 -> "" - default value, not written
+                // 3 -> "abcd\u3110!"
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
+                (byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
+                // 5 -> "Hi"
+                (byte) 0x2a,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+                // 4 -> "Hi"
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        String[] results = new String[4];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0] = pi.readString(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readString(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readString(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readString(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertNull(results[0]);
+        assertNull(results[1]);
+        assertEquals("abcd\u3110!", results[2]);
+        assertEquals("Hi", results[3]);
+    }
+
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat("");
+        testReadCompat("abcd\u3110!");
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(String val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+        final long fieldId = fieldFlags | ((long) 140 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.stringField = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        String result = "";
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readString(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.stringField, result);
+    }
+
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_STRING;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> "" - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> "abcd\u3110!"
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
+                (byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
+                // 4 -> "Hi"
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+
+                // 5 -> "Hi"
+                (byte) 0x2a,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+
+                // 1 -> null - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x00,
+                // 2 -> "" - default value, written when repeated
+                (byte) 0x12,
+                (byte) 0x00,
+                // 3 -> "abcd\u3110!"
+                (byte) 0x1a,
+                (byte) 0x08,
+                (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
+                (byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
+                // 4 -> "Hi"
+                (byte) 0x22,
+                (byte) 0x02,
+                (byte) 0x48, (byte) 0x69,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        String[][] results = new String[4][2];
+        int[] indices = new int[4];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readString(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readString(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readString(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readString(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals("", results[0][0]);
+        assertEquals("", results[0][1]);
+        assertEquals("", results[1][0]);
+        assertEquals("", results[1][1]);
+        assertEquals("abcd\u3110!", results[2][0]);
+        assertEquals("abcd\u3110!", results[2][1]);
+        assertEquals("Hi", results[3][0]);
+        assertEquals("Hi", results[3][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new String[0]);
+        testRepeatedCompat(new String[]{"", "abcd\u3110!", "Hi"});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(String[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_STRING;
+        final long fieldId = fieldFlags | ((long) 141 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.stringFieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        String[] result = new String[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readString(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.stringFieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.stringFieldRepeated[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> {1}
+                (byte) 0x0a,
+                (byte) 0x01,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readString(fieldId1);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId2:
+                        pi.readString(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readString(fieldId3);
+                        // don't fail, length delimited is ok (represents packed booleans)
+                        break;
+                    case (int) fieldId6:
+                        pi.readString(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt32Test.java
new file mode 100644
index 0000000..50fc537
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt32Test.java
@@ -0,0 +1,564 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamUInt32Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[] results = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(int val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+        final long fieldId = fieldFlags | ((long) 50 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint32Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint32Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 6 -> MAX_VALUE
+                (byte) 0x30,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
+        final long fieldId = fieldFlags | ((long) 51 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint32FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint32FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint32FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 6 -> MAX_VALUE
+                (byte) 0x32,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        int[][] results = new int[5][2];
+        int[] indices = new int[5];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readInt(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readInt(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readInt(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readInt(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readInt(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[0]);
+        testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(int[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
+        final long fieldId = fieldFlags | ((long) 52 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint32FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        int[] result = new int[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readInt(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint32FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint32FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readLong(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readInt(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readInt(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readInt(fieldId3);
+                        // don't fail, length delimited is ok (represents packed uint32)
+                        break;
+                    case (int) fieldId6:
+                        pi.readInt(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt64Test.java
new file mode 100644
index 0000000..20969e9
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt64Test.java
@@ -0,0 +1,641 @@
+/*
+ * 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.test.protoinputstream;
+
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.test.protoinputstream.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProtoInputStreamUInt64Test extends TestCase {
+
+    public void testRead() throws IOException {
+        testRead(0);
+        testRead(1);
+        testRead(5);
+    }
+
+    private void testRead(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[] results = new long[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    fail("Should never reach this");
+                    break;
+                case (int) fieldId2:
+                    results[1] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0]);
+        assertEquals(1, results[1]);
+        assertEquals(-1, results[2]);
+        assertEquals(Integer.MIN_VALUE, results[3]);
+        assertEquals(Integer.MAX_VALUE, results[4]);
+        assertEquals(Long.MIN_VALUE, results[5]);
+        assertEquals(Long.MAX_VALUE, results[6]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testReadCompat() throws Exception {
+        testReadCompat(0);
+        testReadCompat(1);
+        testReadCompat(-1);
+        testReadCompat(Integer.MIN_VALUE);
+        testReadCompat(Integer.MAX_VALUE);
+        testReadCompat(Long.MIN_VALUE);
+        testReadCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testReadCompat with a given value.
+     */
+    private void testReadCompat(long val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+        final long fieldId = fieldFlags | ((long) 60 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint64Field = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long result = 0; // start off with default value
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint64Field, result);
+    }
+
+    public void testRepeated() throws IOException {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    private void testRepeated(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x40,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x08,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x10,
+                (byte) 0x01,
+                // 3 -> -1
+                (byte) 0x18,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x20,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x28,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x30,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x38,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testRepeatedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
+        final long fieldId = fieldFlags | ((long) 61 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint64FieldRepeated = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint64FieldRepeated.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint64FieldRepeated[i], result[i]);
+        }
+    }
+
+    public void testPacked() throws IOException {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    private void testPacked(int chunkSize) throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
+        final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+        final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
+        final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 0 - default value, written when repeated
+                (byte) 0x0a,
+                (byte) 0x02,
+                (byte) 0x00,
+                (byte) 0x00,
+                // 2 -> 1
+                (byte) 0x12,
+                (byte) 0x02,
+                (byte) 0x01,
+                (byte) 0x01,
+
+                // 8 -> Integer.MAX_VALUE
+                (byte) 0x42,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 3 -> -1
+                (byte) 0x1a,
+                (byte) 0x14,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 4 -> Integer.MIN_VALUE
+                (byte) 0x22,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
+
+                // 5 -> Integer.MAX_VALUE
+                (byte) 0x2a,
+                (byte) 0x0a,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
+
+                // 6 -> Long.MIN_VALUE
+                (byte) 0x32,
+                (byte) 0x14,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
+                (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
+
+                // 7 -> Long.MAX_VALUE
+                (byte) 0x3a,
+                (byte) 0x12,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
+        long[][] results = new long[7][2];
+        int[] indices = new int[7];
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId1:
+                    results[0][indices[0]++] = pi.readLong(fieldId1);
+                    break;
+                case (int) fieldId2:
+                    results[1][indices[1]++] = pi.readLong(fieldId2);
+                    break;
+                case (int) fieldId3:
+                    results[2][indices[2]++] = pi.readLong(fieldId3);
+                    break;
+                case (int) fieldId4:
+                    results[3][indices[3]++] = pi.readLong(fieldId4);
+                    break;
+                case (int) fieldId5:
+                    results[4][indices[4]++] = pi.readLong(fieldId5);
+                    break;
+                case (int) fieldId6:
+                    results[5][indices[5]++] = pi.readLong(fieldId6);
+                    break;
+                case (int) fieldId7:
+                    results[6][indices[6]++] = pi.readLong(fieldId7);
+                    break;
+                case (int) fieldId8:
+                    // Intentionally don't read the data. Parse should continue normally
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+        stream.close();
+
+        assertEquals(0, results[0][0]);
+        assertEquals(0, results[0][1]);
+        assertEquals(1, results[1][0]);
+        assertEquals(1, results[1][1]);
+        assertEquals(-1, results[2][0]);
+        assertEquals(-1, results[2][1]);
+        assertEquals(Integer.MIN_VALUE, results[3][0]);
+        assertEquals(Integer.MIN_VALUE, results[3][1]);
+        assertEquals(Integer.MAX_VALUE, results[4][0]);
+        assertEquals(Integer.MAX_VALUE, results[4][1]);
+        assertEquals(Long.MIN_VALUE, results[5][0]);
+        assertEquals(Long.MIN_VALUE, results[5][1]);
+        assertEquals(Long.MAX_VALUE, results[6][0]);
+        assertEquals(Long.MAX_VALUE, results[6][1]);
+    }
+
+    /**
+     * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[0]);
+        testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    private void testPackedCompat(long[] val) throws Exception {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
+        final long fieldId = fieldFlags | ((long) 62 & 0x0ffffffffL);
+
+        final Test.All all = new Test.All();
+        all.uint64FieldPacked = val;
+
+        final byte[] proto = MessageNano.toByteArray(all);
+
+        final ProtoInputStream pi = new ProtoInputStream(proto);
+        final Test.All readback = Test.All.parseFrom(proto);
+
+        long[] result = new long[val.length];
+        int index = 0;
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pi.getFieldNumber()) {
+                case (int) fieldId:
+                    result[index++] = pi.readLong(fieldId);
+                    break;
+                default:
+                    fail("Unexpected field id " + pi.getFieldNumber());
+            }
+        }
+
+        assertEquals(readback.uint64FieldPacked.length, result.length);
+        for (int i = 0; i < result.length; i++) {
+            assertEquals(readback.uint64FieldPacked[i], result[i]);
+        }
+    }
+
+    /**
+     * Test that using the wrong read method throws an exception
+     */
+    public void testBadReadType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+        };
+
+        ProtoInputStream pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readFloat(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readDouble(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readInt(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBoolean(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readBytes(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+
+        pi = new ProtoInputStream(protobuf);
+        pi.isNextField(fieldId1);
+        try {
+            pi.readString(fieldId1);
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            // good
+        }
+    }
+
+    /**
+     * Test that unexpected wrong wire types will throw an exception
+     */
+    public void testBadWireType() throws IOException {
+        final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
+
+        final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
+        final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
+        final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
+        final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
+
+        final byte[] protobuf = new byte[]{
+                // 1 : varint -> 1
+                (byte) 0x08,
+                (byte) 0x01,
+                // 2 : fixed64 -> 0x1
+                (byte) 0x11,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                // 3 : length delimited -> { 1 }
+                (byte) 0x1a,
+                (byte) 0x01,
+                (byte) 0x01,
+                // 6 : fixed32
+                (byte) 0x35,
+                (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        };
+
+        InputStream stream = new ByteArrayInputStream(protobuf);
+        final ProtoInputStream pi = new ProtoInputStream(stream);
+
+        while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            try {
+                switch (pi.getFieldNumber()) {
+                    case (int) fieldId1:
+                        pi.readLong(fieldId1);
+                        // don't fail, varint is ok
+                        break;
+                    case (int) fieldId2:
+                        pi.readLong(fieldId2);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    case (int) fieldId3:
+                        pi.readLong(fieldId3);
+                        // don't fail, length delimited is ok (represents packed uint64)
+                        break;
+                    case (int) fieldId6:
+                        pi.readLong(fieldId6);
+                        fail("Should have thrown a WireTypeMismatchException");
+                        break;
+                    default:
+                        fail("Unexpected field id " + pi.getFieldNumber());
+                }
+            } catch (WireTypeMismatchException wtme) {
+                // good
+            }
+        }
+        stream.close();
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoTests.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoTests.java
new file mode 100644
index 0000000..cdf6ae2
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoTests.java
@@ -0,0 +1,45 @@
+/*
+ * 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.test.protoinputstream;
+
+import junit.framework.TestSuite;
+
+public class ProtoTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(ProtoTests.class.getName());
+
+        suite.addTestSuite(ProtoInputStreamDoubleTest.class);
+        suite.addTestSuite(ProtoInputStreamFloatTest.class);
+        suite.addTestSuite(ProtoInputStreamInt32Test.class);
+        suite.addTestSuite(ProtoInputStreamInt64Test.class);
+        suite.addTestSuite(ProtoInputStreamUInt32Test.class);
+        suite.addTestSuite(ProtoInputStreamUInt64Test.class);
+        suite.addTestSuite(ProtoInputStreamSInt32Test.class);
+        suite.addTestSuite(ProtoInputStreamSInt64Test.class);
+        suite.addTestSuite(ProtoInputStreamFixed32Test.class);
+        suite.addTestSuite(ProtoInputStreamFixed64Test.class);
+        suite.addTestSuite(ProtoInputStreamSFixed32Test.class);
+        suite.addTestSuite(ProtoInputStreamSFixed64Test.class);
+        suite.addTestSuite(ProtoInputStreamBoolTest.class);
+        suite.addTestSuite(ProtoInputStreamStringTest.class);
+        suite.addTestSuite(ProtoInputStreamBytesTest.class);
+        suite.addTestSuite(ProtoInputStreamEnumTest.class);
+        suite.addTestSuite(ProtoInputStreamObjectTest.class);
+
+        return suite;
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/test.proto b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/test.proto
new file mode 100644
index 0000000..9ff1d7e
--- /dev/null
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/test.proto
@@ -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.
+ */
+
+syntax = "proto2";
+
+package com.android.test.protoinputstream;
+
+/**
+ * Enum that outside the scope of any classes.
+ */
+enum Outside {
+    OUTSIDE_0 = 0;
+    OUTSIDE_1 = 1;
+};
+
+/**
+ * Message that is recursive.
+ */
+message Nested {
+    optional int32 data = 10001;
+    optional Nested nested = 10002;
+};
+
+/**
+ * Message with all of the field types.
+ */
+message All {
+    /**
+     * Enum that is inside the scope of a class.
+     */
+    enum Inside {
+        option allow_alias = true;
+        INSIDE_0 = 0;
+        INSIDE_1 = 1;
+        INSIDE_1A = 1;
+    };
+
+    optional double double_field = 10;
+    repeated double double_field_repeated = 11;
+    repeated double double_field_packed = 12 [packed=true];
+
+    optional float float_field = 20;
+    repeated float float_field_repeated = 21;
+    repeated float float_field_packed = 22 [packed=true];
+
+    optional int32 int32_field = 30;
+    repeated int32 int32_field_repeated = 31;
+    repeated int32 int32_field_packed = 32 [packed=true];
+
+    optional int64 int64_field = 40;
+    repeated int64 int64_field_repeated = 41;
+    repeated int64 int64_field_packed = 42 [packed=true];
+
+    optional uint32 uint32_field = 50;
+    repeated uint32 uint32_field_repeated = 51;
+    repeated uint32 uint32_field_packed = 52 [packed=true];
+
+    optional uint64 uint64_field = 60;
+    repeated uint64 uint64_field_repeated = 61;
+    repeated uint64 uint64_field_packed = 62 [packed=true];
+
+    optional sint32 sint32_field = 70;
+    repeated sint32 sint32_field_repeated = 71;
+    repeated sint32 sint32_field_packed = 72 [packed=true];
+
+    optional sint64 sint64_field = 80;
+    repeated sint64 sint64_field_repeated = 81;
+    repeated sint64 sint64_field_packed = 82 [packed=true];
+
+    optional fixed32 fixed32_field = 90;
+    repeated fixed32 fixed32_field_repeated = 91;
+    repeated fixed32 fixed32_field_packed = 92 [packed=true];
+
+    optional fixed64 fixed64_field = 100;
+    repeated fixed64 fixed64_field_repeated = 101;
+    repeated fixed64 fixed64_field_packed = 102 [packed=true];
+
+    optional sfixed32 sfixed32_field = 110;
+    repeated sfixed32 sfixed32_field_repeated = 111;
+    repeated sfixed32 sfixed32_field_packed = 112 [packed=true];
+
+    optional sfixed64 sfixed64_field = 120;
+    repeated sfixed64 sfixed64_field_repeated = 121;
+    repeated sfixed64 sfixed64_field_packed = 122 [packed=true];
+
+    optional bool bool_field = 130;
+    repeated bool bool_field_repeated = 131;
+    repeated bool bool_field_packed = 132 [packed=true];
+
+    optional string string_field = 140;
+    repeated string string_field_repeated = 141;
+
+    optional bytes bytes_field = 150;
+    repeated bytes bytes_field_repeated = 151;
+
+    optional Outside outside_field = 160;
+    repeated Outside outside_field_repeated = 161;
+    repeated Outside outside_field_packed = 162 [packed=true];
+
+    optional Nested nested_field = 170;
+    repeated Nested nested_field_repeated = 171;
+};
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 70b4089..c8ef82e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -4,6 +4,7 @@
 java_defaults {
     name: "FrameworksNetTests-jni-defaults",
     static_libs: [
+        "FrameworksNetCommonTests",
         "frameworks-base-testutils",
         "framework-protos",
         "androidx.test.rules",
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
new file mode 100644
index 0000000..0a1ac75
--- /dev/null
+++ b/tests/net/common/Android.bp
@@ -0,0 +1,29 @@
+//
+// 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.
+//
+
+// Tests in this folder are included both in unit tests and CTS.
+// They must be fast and stable, and exercise public or test APIs.
+java_library {
+    name: "FrameworksNetCommonTests",
+    srcs: ["java/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "junit",
+    ],
+    libs: [
+        "android.test.base.stubs",
+    ],
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
similarity index 84%
rename from tests/net/java/android/net/IpPrefixTest.java
rename to tests/net/common/java/android/net/IpPrefixTest.java
index abf019a..719960d 100644
--- a/tests/net/java/android/net/IpPrefixTest.java
+++ b/tests/net/common/java/android/net/IpPrefixTest.java
@@ -39,7 +39,7 @@
 @SmallTest
 public class IpPrefixTest {
 
-    private static InetAddress Address(String addr) {
+    private static InetAddress address(String addr) {
         return InetAddress.parseNumericAddress(addr);
     }
 
@@ -58,59 +58,59 @@
         try {
             p = new IpPrefix((byte[]) null, 9);
             fail("Expected NullPointerException: null byte array");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
         try {
             p = new IpPrefix((InetAddress) null, 10);
             fail("Expected NullPointerException: null InetAddress");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
         try {
             p = new IpPrefix((String) null);
             fail("Expected NullPointerException: null String");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
 
         try {
             byte[] b2 = {1, 2, 3, 4, 5};
             p = new IpPrefix(b2, 29);
             fail("Expected IllegalArgumentException: invalid array length");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
 
         try {
             p = new IpPrefix("1.2.3.4");
             fail("Expected IllegalArgumentException: no prefix length");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
 
         try {
             p = new IpPrefix("1.2.3.4/");
             fail("Expected IllegalArgumentException: empty prefix length");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
 
         try {
             p = new IpPrefix("foo/32");
             fail("Expected IllegalArgumentException: invalid address");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
 
         try {
             p = new IpPrefix("1/32");
             fail("Expected IllegalArgumentException: deprecated IPv4 format");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
 
         try {
             p = new IpPrefix("1.2.3.256/32");
             fail("Expected IllegalArgumentException: invalid IPv4 address");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
 
         try {
             p = new IpPrefix("foo/32");
             fail("Expected IllegalArgumentException: non-address");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
 
         try {
             p = new IpPrefix("f00:::/32");
             fail("Expected IllegalArgumentException: invalid IPv6 address");
-        } catch(IllegalArgumentException expected) {}
+        } catch (IllegalArgumentException expected) { }
     }
 
     @Test
@@ -132,17 +132,17 @@
         try {
             p = new IpPrefix(IPV4_BYTES, 33);
             fail("Expected IllegalArgumentException: invalid prefix length");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
         try {
             p = new IpPrefix(IPV4_BYTES, 128);
             fail("Expected IllegalArgumentException: invalid prefix length");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
         try {
             p = new IpPrefix(IPV4_BYTES, -1);
             fail("Expected IllegalArgumentException: negative prefix length");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
         p = new IpPrefix(IPV6_BYTES, 128);
         assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
@@ -162,12 +162,12 @@
         try {
             p = new IpPrefix(IPV6_BYTES, -1);
             fail("Expected IllegalArgumentException: negative prefix length");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
         try {
             p = new IpPrefix(IPV6_BYTES, 129);
             fail("Expected IllegalArgumentException: negative prefix length");
-        } catch(RuntimeException expected) {}
+        } catch (RuntimeException expected) { }
 
     }
 
@@ -226,28 +226,28 @@
     @Test
     public void testContainsInetAddress() {
         IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
-        assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
-        assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
-        assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
-        assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
-        assertFalse(p.contains(Address("2001:4868:4860::8888")));
-        assertFalse(p.contains(Address("8.8.8.8")));
+        assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
+        assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
+        assertFalse(p.contains(address("2001:db8:f00::ace:d00e")));
+        assertFalse(p.contains(address("2001:db8:f00::bad:d00d")));
+        assertFalse(p.contains(address("2001:4868:4860::8888")));
+        assertFalse(p.contains(address("8.8.8.8")));
 
         p = new IpPrefix("192.0.2.0/23");
-        assertTrue(p.contains(Address("192.0.2.43")));
-        assertTrue(p.contains(Address("192.0.3.21")));
-        assertFalse(p.contains(Address("192.0.0.21")));
-        assertFalse(p.contains(Address("8.8.8.8")));
-        assertFalse(p.contains(Address("2001:4868:4860::8888")));
+        assertTrue(p.contains(address("192.0.2.43")));
+        assertTrue(p.contains(address("192.0.3.21")));
+        assertFalse(p.contains(address("192.0.0.21")));
+        assertFalse(p.contains(address("8.8.8.8")));
+        assertFalse(p.contains(address("2001:4868:4860::8888")));
 
         IpPrefix ipv6Default = new IpPrefix("::/0");
-        assertTrue(ipv6Default.contains(Address("2001:db8::f00")));
-        assertFalse(ipv6Default.contains(Address("192.0.2.1")));
+        assertTrue(ipv6Default.contains(address("2001:db8::f00")));
+        assertFalse(ipv6Default.contains(address("192.0.2.1")));
 
         IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
-        assertTrue(ipv4Default.contains(Address("255.255.255.255")));
-        assertTrue(ipv4Default.contains(Address("192.0.2.1")));
-        assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
+        assertTrue(ipv4Default.contains(address("255.255.255.255")));
+        assertTrue(ipv4Default.contains(address("192.0.2.1")));
+        assertFalse(ipv4Default.contains(address("2001:db8::f00")));
     }
 
     @Test
@@ -315,10 +315,10 @@
                 p = new IpPrefix(b, random.nextInt(129));
             }
             if (p.equals(oldP)) {
-              assertEquals(p.hashCode(), oldP.hashCode());
+                assertEquals(p.hashCode(), oldP.hashCode());
             }
             if (p.hashCode() != oldP.hashCode()) {
-              assertNotEquals(p, oldP);
+                assertNotEquals(p, oldP);
             }
         }
     }
@@ -332,9 +332,9 @@
             new IpPrefix("0.0.0.0/0"),
         };
         for (int i = 0; i < prefixes.length; i++) {
-          for (int j = i + 1; j < prefixes.length; j++) {
-            assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
-          }
+            for (int j = i + 1; j < prefixes.length; j++) {
+                assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
+            }
         }
     }
 
@@ -371,8 +371,8 @@
     }
 
     public void assertParcelingIsLossless(IpPrefix p) {
-      IpPrefix p2 = passThroughParcel(p);
-      assertEquals(p, p2);
+        IpPrefix p2 = passThroughParcel(p);
+        assertEquals(p, p2);
     }
 
     @Test
diff --git a/tests/net/java/android/net/NetworkStackTest.java b/tests/net/java/android/net/NetworkStackTest.java
new file mode 100644
index 0000000..f7c6c99
--- /dev/null
+++ b/tests/net/java/android/net/NetworkStackTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.net;
+
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+import static android.net.NetworkStack.checkNetworkStackPermission;
+import static android.net.NetworkStack.checkNetworkStackPermissionOr;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.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)
+public class NetworkStackTest {
+    private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"};
+
+    @Mock Context mCtx;
+
+    @Before public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testCheckNetworkStackPermission() throws Exception {
+        when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED);
+        when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
+                .thenReturn(PERMISSION_DENIED);
+        checkNetworkStackPermission(mCtx);
+        checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+
+        when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED);
+        when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
+                .thenReturn(PERMISSION_GRANTED);
+        checkNetworkStackPermission(mCtx);
+        checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+
+        when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED);
+
+        try {
+            checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+        } catch (SecurityException e) {
+            // Expect to get a SecurityException
+            return;
+        }
+
+        fail("Expect fail but permission granted.");
+    }
+}
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index b6038ab..2adbb06 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -45,6 +45,7 @@
 import libcore.util.HexEncoding;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -189,6 +190,7 @@
         udp.close();
     }
 
+    @Ignore
     @Test
     public void testGetConnectionOwnerUid() throws Exception {
         checkGetConnectionOwnerUid("::", null);
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 68ff777..22a2c94 100644
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.eq;
@@ -134,11 +135,11 @@
         IBinder binderMock = mock(IBinder.class);
         doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
 
-        RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
-
-        // Verify that cleanup is performed (Spy limitations prevent verification of method calls
-        // for binder death scenario; check refcount to determine if cleanup was performed.)
-        assertEquals(-1, refcountedResource.mRefCount);
+        try {
+            getTestRefcountedResource(binderMock);
+            fail("Expected exception to propogate when binder fails to link to death");
+        } catch (RuntimeException expected) {
+        }
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index b5c3e92..4a35015 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -156,10 +156,21 @@
 
     @Test
     public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
-        int localport = findUnusedPort();
+        int localport = -1;
+        IpSecUdpEncapResponse udpEncapResp = null;
 
-        IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+        for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
+            localport = findUnusedPort();
+
+            udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+            assertNotNull(udpEncapResp);
+            if (udpEncapResp.status == IpSecManager.Status.OK) {
+                break;
+            }
+
+            // Else retry to reduce possibility for port-bind failures.
+        }
+
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
         assertEquals(localport, udpEncapResp.port);
@@ -204,12 +215,11 @@
 
     @Test
     public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
-        int localport = findUnusedPort();
         IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-        assertEquals(localport, udpEncapResp.port);
+        int localport = udpEncapResp.port;
 
         mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
         udpEncapResp.fileDescriptor.close();
@@ -226,12 +236,11 @@
      */
     @Test
     public void testUdpEncapPortNotReleased() throws Exception {
-        int localport = findUnusedPort();
         IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-        assertEquals(localport, udpEncapResp.port);
+        int localport = udpEncapResp.port;
 
         udpEncapResp.fileDescriptor.close();
 
@@ -273,14 +282,11 @@
 
     @Test
     public void testOpenUdpEncapsulationSocketTwice() throws Exception {
-        int localport = findUnusedPort();
-
         IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-        assertEquals(localport, udpEncapResp.port);
-        mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+        int localport = udpEncapResp.port;
 
         IpSecUdpEncapResponse testUdpEncapResp =
                 mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
index 548a0c22..5fb23b0 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
@@ -40,7 +40,7 @@
     @SmallTest
     public void testREORDER_TASKS() {
         try {
-            mAm.moveTaskToFront(0, 0, null);
+            mAm.moveTaskToFront(null, null, 0, 0, null);
             fail("IActivityManager.moveTaskToFront did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 4e6d073..1aad4be 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1177,7 +1177,7 @@
 
         // Initialize the buffer with list data type.
         fprintf(out, "        buff[pos] = LIST_TYPE;\n");
-        fprintf(out, "        buff[pos + 1] = %lu;\n", signature.size() + 2);
+        fprintf(out, "        buff[pos + 1] = %zu;\n", signature.size() + 2);
         fprintf(out, "        pos += LIST_TYPE_OVERHEAD;\n");
 
         // Write timestamp.
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 1e46d1b..b07d8ed 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -213,7 +213,7 @@
      * Builder used to build {@link ConfigRequest} objects.
      */
     public static final class Builder {
-        private boolean mSupport5gBand = false;
+        private boolean mSupport5gBand = true;
         private int mMasterPreference = 0;
         private int mClusterLow = CLUSTER_ID_MIN;
         private int mClusterHigh = CLUSTER_ID_MAX;
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 52bb284..db8220b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -576,7 +576,7 @@
                 equalTo(configRequest.mClusterLow));
         collector.checkThat("mMasterPreference", 0,
                 equalTo(configRequest.mMasterPreference));
-        collector.checkThat("mSupport5gBand", false, equalTo(configRequest.mSupport5gBand));
+        collector.checkThat("mSupport5gBand", true, equalTo(configRequest.mSupport5gBand));
         collector.checkThat("mDiscoveryWindowInterval.length", 2,
                 equalTo(configRequest.mDiscoveryWindowInterval.length));
         collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,