Merge "Zygote: Restore GL preload"
diff --git a/Android.mk b/Android.mk
index 22323c5..9e89738 100644
--- a/Android.mk
+++ b/Android.mk
@@ -265,8 +265,9 @@
 	core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
 	core/java/android/service/autofill/IAutoFillAppCallback.aidl \
 	core/java/android/service/autofill/IAutoFillManagerService.aidl \
-	core/java/android/service/autofill/IAutoFillServerCallback.aidl \
 	core/java/android/service/autofill/IAutoFillService.aidl \
+	core/java/android/service/autofill/IFillCallback.aidl \
+	core/java/android/service/autofill/ISaveCallback.aidl \
 	core/java/android/service/carrier/ICarrierService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
@@ -294,6 +295,10 @@
 	core/java/android/print/IWriteResultCallback.aidl \
 	core/java/android/printservice/IPrintService.aidl \
 	core/java/android/printservice/IPrintServiceClient.aidl \
+	core/java/android/companion/ICompanionDeviceManager.aidl \
+	core/java/android/companion/ICompanionDeviceManagerService.aidl \
+	core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl \
+	core/java/android/companion/IOnAssociateCallback.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \
@@ -365,6 +370,7 @@
 	core/java/com/android/internal/statusbar/IStatusBar.aidl \
 	core/java/com/android/internal/statusbar/IStatusBarService.aidl \
 	core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
+	core/java/com/android/internal/textservice/ISpellCheckerServiceCallback.aidl \
 	core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \
 	core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
 	core/java/com/android/internal/textservice/ITextServicesManager.aidl \
@@ -383,6 +389,7 @@
 	core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
 	keystore/java/android/security/IKeyChainAliasCallback.aidl \
 	keystore/java/android/security/IKeyChainService.aidl \
+	location/java/android/location/IBatchedLocationCallback.aidl \
 	location/java/android/location/ICountryDetector.aidl \
 	location/java/android/location/ICountryListener.aidl \
 	location/java/android/location/IFusedProvider.aidl \
diff --git a/api/current.txt b/api/current.txt
index eac0653..6d9027a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -79,6 +79,7 @@
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
     field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
+    field public static final java.lang.String INSTANT_APP_FOREGROUND_SERVICE = "android.permission.INSTANT_APP_FOREGROUND_SERVICE";
     field public static final java.lang.String INTERNET = "android.permission.INTERNET";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
@@ -118,6 +119,7 @@
     field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+    field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -203,7 +205,6 @@
 
   public static final class R.attr {
     ctor public R.attr();
-    field public static final int __removed0 = 16844097; // 0x1010541
     field public static final int __removed1 = 16844099; // 0x1010543
     field public static final int absListViewStyle = 16842858; // 0x101006a
     field public static final int accessibilityEventTypes = 16843648; // 0x1010380
@@ -269,6 +270,7 @@
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
     field public static final int allowUndo = 16843999; // 0x10104df
     field public static final int alpha = 16843551; // 0x101031f
+    field public static final int alphabeticModifiers = 16844112; // 0x1010550
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
     field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
@@ -923,6 +925,7 @@
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
+    field public static final int numericModifiers = 16844113; // 0x1010551
     field public static final int numericShortcut = 16843236; // 0x10101e4
     field public static final int offset = 16844052; // 0x1010514
     field public static final int onClick = 16843375; // 0x101026f
@@ -1270,6 +1273,7 @@
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetName = 16843853; // 0x101044d
     field public static final int targetPackage = 16842785; // 0x1010021
+    field public static final int targetProcess = 16844097; // 0x1010541
     field public static final int targetSandboxVersion = 16844110; // 0x101054e
     field public static final int targetSdkVersion = 16843376; // 0x1010270
     field public static final int taskAffinity = 16842770; // 0x1010012
@@ -2688,11 +2692,25 @@
 
 package android.accessibilityservice {
 
+  public final class AccessibilityButtonController {
+    method public boolean isAccessibilityButtonAvailable();
+    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, android.os.Handler);
+    method public void unregisterAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+  }
+
+  public static abstract class AccessibilityButtonController.AccessibilityButtonCallback {
+    ctor public AccessibilityButtonController.AccessibilityButtonCallback();
+    method public void onAvailabilityChanged(android.accessibilityservice.AccessibilityButtonController, boolean);
+    method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
+  }
+
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
     method public final void disableSelf();
     method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
     method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
@@ -2805,6 +2823,7 @@
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
     field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
     field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
@@ -2909,7 +2928,7 @@
   public class AccountManager {
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
-    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, java.lang.Integer>);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[]);
     method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -2918,7 +2937,7 @@
     method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
-    method public int getAccountVisibility(android.accounts.Account, int);
+    method public int getAccountVisibility(android.accounts.Account, java.lang.String);
     method public android.accounts.Account[] getAccounts();
     method public java.util.Map<android.accounts.Account, java.lang.Integer> getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String);
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2929,9 +2948,9 @@
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
+    method public java.util.Map<java.lang.String, java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
-    method public java.util.Map<java.lang.Integer, java.lang.Integer> getUidsAndVisibilityForAccount(android.accounts.Account);
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
@@ -2945,7 +2964,7 @@
     method public boolean removeAccountExplicitly(android.accounts.Account);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
     method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
-    method public boolean setAccountVisibility(android.accounts.Account, int, int);
+    method public boolean setAccountVisibility(android.accounts.Account, java.lang.String, int);
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
@@ -2985,8 +3004,8 @@
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
     field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
-    field public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3; // 0xfffffffd
-    field public static final int UID_KEY_DEFAULT_VISIBILITY = -2; // 0xfffffffe
+    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
+    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
     field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
     field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
     field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -4804,6 +4823,7 @@
     method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    method public void addResults(android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnDestroy(android.app.Activity);
@@ -4828,6 +4848,7 @@
     method public android.os.Bundle getBinderCounts();
     method public android.content.ComponentName getComponentName();
     method public android.content.Context getContext();
+    method public java.lang.String getProcessName();
     method public android.content.Context getTargetContext();
     method public android.app.UiAutomation getUiAutomation();
     method public android.app.UiAutomation getUiAutomation(int);
@@ -5044,14 +5065,19 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public int getBadgeIcon();
     method public java.lang.String getChannel();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
+    method public java.lang.String getShortcutId();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public long getTimeout();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
+    field public static final int BADGE_ICON_LARGE = 2; // 0x2
+    field public static final int BADGE_ICON_NONE = 0; // 0x0
+    field public static final int BADGE_ICON_SMALL = 1; // 0x1
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
     field public static final java.lang.String CATEGORY_CALL = "call";
     field public static final java.lang.String CATEGORY_EMAIL = "email";
@@ -5143,7 +5169,7 @@
     field public deprecated int ledARGB;
     field public deprecated int ledOffMS;
     field public deprecated int ledOnMS;
-    field public deprecated int number;
+    field public int number;
     field public deprecated int priority;
     field public android.app.Notification publicVersion;
     field public deprecated android.net.Uri sound;
@@ -5231,6 +5257,7 @@
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
+    method public android.app.Notification.Builder chooseBadgeIcon(int);
     method public android.widget.RemoteViews createBigContentView();
     method public android.widget.RemoteViews createContentView();
     method public android.widget.RemoteViews createHeadsUpContentView();
@@ -5263,13 +5290,14 @@
     method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
     method public deprecated android.app.Notification.Builder setLights(int, int, int);
     method public android.app.Notification.Builder setLocalOnly(boolean);
-    method public deprecated android.app.Notification.Builder setNumber(int);
+    method public android.app.Notification.Builder setNumber(int);
     method public android.app.Notification.Builder setOngoing(boolean);
     method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
     method public deprecated android.app.Notification.Builder setPriority(int);
     method public android.app.Notification.Builder setProgress(int, int, boolean);
     method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
     method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+    method public android.app.Notification.Builder setShortcutId(java.lang.String);
     method public android.app.Notification.Builder setShowWhen(boolean);
     method public android.app.Notification.Builder setSmallIcon(int);
     method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5447,11 +5475,13 @@
     method public boolean canBypassDnd();
     method public boolean canShowBadge();
     method public int describeContents();
+    method public void enableLights(boolean);
     method public void enableVibration(boolean);
     method public android.media.AudioAttributes getAudioAttributes();
     method public java.lang.String getGroup();
     method public java.lang.String getId();
     method public int getImportance();
+    method public int getLightColor();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
@@ -5459,7 +5489,7 @@
     method public void setBypassDnd(boolean);
     method public void setGroup(java.lang.String);
     method public void setImportance(int);
-    method public void setLights(boolean);
+    method public void setLightColor(int);
     method public void setLockscreenVisibility(int);
     method public void setShowBadge(boolean);
     method public void setSound(android.net.Uri, android.media.AudioAttributes);
@@ -5653,10 +5683,11 @@
   }
 
   public final class RemoteAction implements android.os.Parcelable {
-    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.RemoteAction clone();
     method public int describeContents();
     method public void dump(java.lang.String, java.io.PrintWriter);
+    method public android.app.PendingIntent getActionIntent();
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getTitle();
@@ -5664,10 +5695,6 @@
     field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
   }
 
-  public static abstract interface RemoteAction.OnActionListener {
-    method public abstract void onAction(android.app.RemoteAction);
-  }
-
   public final class RemoteInput implements android.os.Parcelable {
     method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
@@ -6193,6 +6220,7 @@
     method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+    method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
     method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
@@ -7941,6 +7969,65 @@
 
 }
 
+package android.companion {
+
+  public final class AssociationRequest<F extends android.companion.DeviceFilter> implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+  }
+
+  public static final class AssociationRequest.Builder<F extends android.companion.DeviceFilter> {
+    method public android.companion.AssociationRequest<F> build();
+    method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothDeviceFilter> createForBluetoothDevice();
+    method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothLEDeviceFilter> createForBluetoothLEDevice();
+    method public android.companion.AssociationRequest.Builder<F> setDeviceFilter(F);
+    method public android.companion.AssociationRequest.Builder<F> setSingleDevice(boolean);
+  }
+
+  public final class BluetoothDeviceFilter implements android.companion.DeviceFilter {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.BluetoothDeviceFilter> CREATOR;
+  }
+
+  public static final class BluetoothDeviceFilter.Builder {
+    ctor public BluetoothDeviceFilter.Builder();
+    method public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
+    method public android.companion.BluetoothDeviceFilter build();
+    method public android.companion.BluetoothDeviceFilter.Builder setAddress(java.lang.String);
+    method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+  }
+
+  public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+  }
+
+  public static final class BluetoothLEDeviceFilter.Builder {
+    ctor public BluetoothLEDeviceFilter.Builder();
+    method public android.companion.BluetoothLEDeviceFilter build();
+    method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+    method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
+  }
+
+  public final class CompanionDeviceManager {
+    method public void associate(android.companion.AssociationRequest<?>, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
+    field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+  }
+
+  public static abstract class CompanionDeviceManager.Callback {
+    ctor public CompanionDeviceManager.Callback();
+    method public abstract void onDeviceFound(android.content.IntentSender);
+    method public abstract void onFailure(java.lang.CharSequence);
+  }
+
+  public abstract interface DeviceFilter<D extends android.os.Parcelable> implements android.os.Parcelable {
+  }
+
+}
+
 package android.content {
 
   public abstract class AbstractThreadedSyncAdapter {
@@ -8553,6 +8640,7 @@
     field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
     field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
+    field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -9090,6 +9178,10 @@
     field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
     field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
     field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+    field public static final java.lang.String EXTRA_AUTO_FILL_ASSIST_STRUCTURE = "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+    field public static final java.lang.String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+    field public static final java.lang.String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+    field public static final java.lang.String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
     field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
     field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
     field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -9903,6 +9995,7 @@
     field public java.lang.String[] splitPublicSourceDirs;
     field public java.lang.String[] splitSourceDirs;
     field public java.lang.String targetPackage;
+    field public java.lang.String targetProcess;
   }
 
   public class LabeledIntent extends android.content.Intent {
@@ -10324,6 +10417,7 @@
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
@@ -20440,6 +20534,7 @@
     method public int getContentType();
     method public int getFlags();
     method public int getUsage();
+    method public static int getVolumeControlStream(android.media.AudioAttributes);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
     field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -21900,6 +21995,7 @@
     method public boolean advance();
     method public long getCachedDuration();
     method public android.media.DrmInitData getDrmInitData();
+    method public android.os.Bundle getMetrics();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -23583,6 +23679,8 @@
 
   public final class MediaController {
     ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
+    method public void addQueueItem(android.media.MediaDescription);
+    method public void addQueueItem(android.media.MediaDescription, int);
     method public void adjustVolume(int, int);
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public android.os.Bundle getExtras();
@@ -23601,6 +23699,8 @@
     method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
+    method public void removeQueueItem(android.media.MediaDescription);
+    method public void removeQueueItemAt(int);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void setVolumeTo(int, int);
     method public void unregisterCallback(android.media.session.MediaController.Callback);
@@ -23678,11 +23778,14 @@
     method public void setSessionActivity(android.app.PendingIntent);
     method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
   public static abstract class MediaSession.Callback {
     ctor public MediaSession.Callback();
+    method public void onAddQueueItem(android.media.MediaDescription);
+    method public void onAddQueueItem(android.media.MediaDescription, int);
     method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void onCustomAction(java.lang.String, android.os.Bundle);
     method public void onFastForward();
@@ -23696,6 +23799,8 @@
     method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
     method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
     method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+    method public void onRemoveQueueItem(android.media.MediaDescription);
+    method public void onRemoveQueueItemAt(int);
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
@@ -23853,6 +23958,31 @@
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
+  public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+  }
+
   public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
     field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
   }
@@ -23935,7 +24065,7 @@
     field public static final java.lang.String CONTENT_DIRECTORY = "logo";
   }
 
-  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
+  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
     field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
     field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
     field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
@@ -23944,53 +24074,31 @@
     field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
     field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
     field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_AUTHOR = "author";
     field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
     field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
     field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
     field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
     field public static final java.lang.String COLUMN_LIVE = "live";
     field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
     field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
     field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
     field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
     field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
     field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
     field public static final java.lang.String COLUMN_WEIGHT = "weight";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
@@ -24046,37 +24154,15 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
-  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
     field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
     field public static final android.net.Uri CONTENT_URI;
@@ -25606,7 +25692,7 @@
     field public boolean isHomeProviderNetwork;
     field public int networkId;
     field public java.lang.String preSharedKey;
-    field public int priority;
+    field public deprecated int priority;
     field public java.lang.String providerFriendlyName;
     field public long[] roamingConsortiumIds;
     field public int status;
@@ -25711,11 +25797,14 @@
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
+    field public static final int AKA = 6; // 0x6
+    field public static final int AKA_PRIME = 7; // 0x7
     field public static final int GTC = 4; // 0x4
     field public static final int MSCHAP = 2; // 0x2
     field public static final int MSCHAPV2 = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int PAP = 1; // 0x1
+    field public static final int SIM = 5; // 0x5
   }
 
   public class WifiInfo implements android.os.Parcelable {
@@ -25762,13 +25851,13 @@
     method public boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
     method public boolean isWifiEnabled();
-    method public boolean pingSupplicant();
+    method public deprecated boolean pingSupplicant();
     method public void queryPasspointIcon(long, java.lang.String);
     method public boolean reassociate();
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean removePasspointConfiguration(java.lang.String);
-    method public boolean saveConfiguration();
+    method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -26001,7 +26090,7 @@
     method public java.lang.String getSubscriptionType();
     method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
     method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
-    method public int getUpdateIdentififer();
+    method public int getUpdateIdentifier();
     method public long getUsageLimitDataLimit();
     method public long getUsageLimitStartTimeInMs();
     method public long getUsageLimitTimeLimitInMinutes();
@@ -26043,7 +26132,7 @@
     method public int describeContents();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
-    method public boolean getCheckAaaServerStatus();
+    method public boolean getCheckAaaServerCertStatus();
     method public java.security.cert.X509Certificate[] getClientCertificateChain();
     method public java.security.PrivateKey getClientPrivateKey();
     method public long getCreationTimeInMs();
@@ -26124,7 +26213,7 @@
     method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
     method public java.lang.String getIconUrl();
     method public long[] getMatchAllOis();
-    method public long[] getMatchAnysOis();
+    method public long[] getMatchAnyOis();
     method public java.lang.String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(java.lang.String);
@@ -26146,7 +26235,7 @@
     method public int describeContents();
     method public java.lang.String[] getExcludedSsidList();
     method public int getMaximumBssLoadValue();
-    method public long getMinHomeDownlinkBandWidht();
+    method public long getMinHomeDownlinkBandwidth();
     method public long getMinHomeUplinkBandwidth();
     method public long getMinRoamingDownlinkBandwidth();
     method public long getMinRoamingUplinkBandwidth();
@@ -29758,6 +29847,7 @@
     field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
     field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
     field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
+    field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
     field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
     field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
     field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -36093,26 +36183,19 @@
     ctor public AutoFillService();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
-    method public void onDatasetAuthenticationRequest(android.os.Bundle, int);
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
-    method public void onFillResponseAuthenticationRequest(android.os.Bundle, int);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
-    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
-    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
-    field public static final int FLAG_AUTHENTICATION_ERROR = 4; // 0x4
-    field public static final int FLAG_AUTHENTICATION_REQUESTED = 1; // 0x1
-    field public static final int FLAG_AUTHENTICATION_SUCCESS = 2; // 0x2
-    field public static final int FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE = 8; // 0x8
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
-  public final class FillCallback {
-    method public void onDatasetAuthentication(android.view.autofill.Dataset, int);
+  public final class FillCallback implements android.os.Parcelable {
+    method public int describeContents();
     method public void onFailure(java.lang.CharSequence);
-    method public void onFillResponseAuthentication(int);
     method public void onSuccess(android.view.autofill.FillResponse);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.FillCallback> CREATOR;
   }
 
   public final class SaveCallback {
@@ -36678,6 +36761,7 @@
     method public boolean onKeyUp(int, android.view.KeyEvent);
     method public void onLockscreenShown();
     method public void onLowMemory();
+    method public void onPrepareShow(android.os.Bundle, int);
     method public void onRequestAbortVoice(android.service.voice.VoiceInteractionSession.AbortVoiceRequest);
     method public void onRequestCommand(android.service.voice.VoiceInteractionSession.CommandRequest);
     method public void onRequestCompleteVoice(android.service.voice.VoiceInteractionSession.CompleteVoiceRequest);
@@ -36691,6 +36775,7 @@
     method public void setDisabledShowContext(int);
     method public void setKeepAwake(boolean);
     method public void setTheme(int);
+    method public void setUiEnabled(boolean);
     method public void show(android.os.Bundle, int);
     method public void startVoiceActivity(android.content.Intent);
     field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
@@ -41949,6 +42034,15 @@
     method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
   }
 
+  public abstract class TransitionListenerAdapter implements android.transition.Transition.TransitionListener {
+    ctor public TransitionListenerAdapter();
+    method public void onTransitionCancel(android.transition.Transition);
+    method public void onTransitionEnd(android.transition.Transition);
+    method public void onTransitionPause(android.transition.Transition);
+    method public void onTransitionResume(android.transition.Transition);
+    method public void onTransitionStart(android.transition.Transition);
+  }
+
   public class TransitionManager {
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -43730,6 +43824,7 @@
     field public static final int FLAG_APPEND_TO_GROUP = 1; // 0x1
     field public static final int FLAG_PERFORM_NO_CLOSE = 1; // 0x1
     field public static final int NONE = 0; // 0x0
+    field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f
   }
 
   public class MenuInflater {
@@ -43742,6 +43837,7 @@
     method public abstract boolean expandActionView();
     method public abstract android.view.ActionProvider getActionProvider();
     method public abstract android.view.View getActionView();
+    method public default int getAlphabeticModifiers();
     method public abstract char getAlphabeticShortcut();
     method public default java.lang.CharSequence getContentDescription();
     method public abstract int getGroupId();
@@ -43749,6 +43845,7 @@
     method public abstract android.content.Intent getIntent();
     method public abstract int getItemId();
     method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
+    method public default int getNumericModifiers();
     method public abstract char getNumericShortcut();
     method public abstract int getOrder();
     method public abstract android.view.SubMenu getSubMenu();
@@ -43765,6 +43862,7 @@
     method public abstract android.view.MenuItem setActionView(android.view.View);
     method public abstract android.view.MenuItem setActionView(int);
     method public abstract android.view.MenuItem setAlphabeticShortcut(char);
+    method public default android.view.MenuItem setAlphabeticShortcut(char, int);
     method public abstract android.view.MenuItem setCheckable(boolean);
     method public abstract android.view.MenuItem setChecked(boolean);
     method public default android.view.MenuItem setContentDescription(java.lang.CharSequence);
@@ -43773,9 +43871,11 @@
     method public abstract android.view.MenuItem setIcon(int);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
+    method public default android.view.MenuItem setNumericShortcut(char, int);
     method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
     method public abstract android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener);
     method public abstract android.view.MenuItem setShortcut(char, char);
+    method public default android.view.MenuItem setShortcut(char, char, int, int);
     method public abstract void setShowAsAction(int);
     method public abstract android.view.MenuItem setShowAsActionFlags(int);
     method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
@@ -44265,6 +44365,7 @@
     ctor public View(android.content.Context, android.util.AttributeSet, int);
     ctor public View(android.content.Context, android.util.AttributeSet, int, int);
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
+    method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
     method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
@@ -44274,6 +44375,7 @@
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
     method public void autoFill(android.view.autofill.AutoFillValue);
+    method public void autoFillVirtual(int, android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -44347,8 +44449,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final <T extends android.view.View> T findViewById(int);
-    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
+    method public final android.view.View findViewById(int);
+    method public final android.view.View findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
@@ -44364,7 +44466,7 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.view.autofill.AutoFillType getAutoFillType();
-    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
+    method public android.view.autofill.AutoFillValue getAutoFillValue();
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -44502,6 +44604,7 @@
     method public float getX();
     method public float getY();
     method public float getZ();
+    method public boolean hasExplicitFocusable();
     method public boolean hasFocus();
     method public boolean hasFocusable();
     method public boolean hasNestedScrollingParent();
@@ -44662,7 +44765,7 @@
     method public final void requestUnbufferedDispatch(android.view.MotionEvent);
     method public static int resolveSize(int, int);
     method public static int resolveSizeAndState(int, int, int);
-    method public boolean restoreDefaultFocus(int);
+    method public boolean restoreDefaultFocus();
     method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -44959,6 +45062,7 @@
 
   public static class View.AccessibilityDelegate {
     ctor public View.AccessibilityDelegate();
+    method public void addExtraDataToAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
     method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
@@ -46079,6 +46183,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
     method public deprecated int getActions();
+    method public java.util.List<java.lang.String> getAvailableExtraData();
     method public void getBoundsInParent(android.graphics.Rect);
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -46135,11 +46240,13 @@
     method public boolean performAction(int, android.os.Bundle);
     method public void recycle();
     method public boolean refresh();
+    method public boolean refreshWithExtraData(java.lang.String, android.os.Bundle);
     method public deprecated void removeAction(int);
     method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
     method public boolean removeChild(android.view.View);
     method public boolean removeChild(android.view.View, int);
     method public void setAccessibilityFocused(boolean);
+    method public void setAvailableExtraData(java.util.List<java.lang.String>);
     method public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
     method public void setCanOpenPopup(boolean);
@@ -46222,6 +46329,9 @@
     field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
     field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
     field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
     field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
     field public static final int FOCUS_INPUT = 1; // 0x1
     field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
@@ -46303,6 +46413,7 @@
 
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
+    method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -46713,11 +46824,11 @@
   }
 
   public final class AutoFillManager {
-    method public void onValueChanged(android.view.View, android.view.autofill.AutoFillValue);
-    method public void updateAutoFillInput(android.view.View, int);
-    method public void updateAutoFillInput(android.view.View, int, android.graphics.Rect, int);
-    field public static final int FLAG_UPDATE_UI_HIDE = 2; // 0x2
-    field public static final int FLAG_UPDATE_UI_SHOW = 1; // 0x1
+    method public void focusChanged(android.view.View, boolean);
+    method public void reset();
+    method public void valueChanged(android.view.View);
+    method public void virtualFocusChanged(android.view.View, int, android.graphics.Rect, boolean);
+    method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
   }
 
   public final class AutoFillType implements android.os.Parcelable {
@@ -46752,10 +46863,9 @@
   }
 
   public static final class Dataset.Builder {
-    ctor public Dataset.Builder(java.lang.CharSequence);
+    ctor public Dataset.Builder(java.lang.String, java.lang.CharSequence);
     method public android.view.autofill.Dataset build();
-    method public android.view.autofill.Dataset.Builder requiresCustomAuthentication(android.os.Bundle, int);
-    method public android.view.autofill.Dataset.Builder requiresFingerprintAuthentication(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.Bundle, int);
+    method public android.view.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
     method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
     method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
   }
@@ -46767,27 +46877,14 @@
   }
 
   public static final class FillResponse.Builder {
-    ctor public FillResponse.Builder();
+    ctor public FillResponse.Builder(java.lang.String);
     method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
     method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
     method public android.view.autofill.FillResponse build();
-    method public android.view.autofill.FillResponse.Builder requiresCustomAuthentication(android.os.Bundle, int);
-    method public android.view.autofill.FillResponse.Builder requiresFingerprintAuthentication(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.Bundle, int);
+    method public android.view.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender);
     method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
   }
 
-  public abstract class VirtualViewDelegate {
-    ctor public VirtualViewDelegate();
-    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
-  }
-
-  public static abstract class VirtualViewDelegate.Callback {
-    ctor public VirtualViewDelegate.Callback();
-    method public void onAutoFillInputUpdated(int, android.graphics.Rect, int);
-    method public void onNodeRemoved(int...);
-    method public void onValueChanged(int);
-  }
-
 }
 
 package android.view.inputmethod {
@@ -50283,6 +50380,7 @@
     method public int getAutoSizeMaxTextSize();
     method public int getAutoSizeMinTextSize();
     method public int getAutoSizeStepGranularity();
+    method public int[] getAutoSizeTextPresetSizes();
     method public int getAutoSizeTextType();
     method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
@@ -50396,6 +50494,7 @@
     method public void setAutoSizeMaxTextSize(int, float);
     method public void setAutoSizeMinTextSize(int, float);
     method public void setAutoSizeStepGranularity(int, float);
+    method public void setAutoSizeTextPresetSizes(int[]);
     method public void setAutoSizeTextType(int);
     method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
@@ -50529,6 +50628,7 @@
     method public void setIs24HourView(java.lang.Boolean);
     method public void setMinute(int);
     method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+    method public boolean validateInput();
   }
 
   public static abstract interface TimePicker.OnTimeChangedListener {
@@ -50927,6 +51027,8 @@
     field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
     field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
     field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+    field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+    field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
     field public static final int OP_INVOKE_STATIC = 113; // 0x71
     field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
     field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -54221,12 +54323,15 @@
   }
 
   public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
     method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
     method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
     method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
     method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
     method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
     method public boolean isVarargsCollector();
     method public java.lang.invoke.MethodType type();
@@ -54260,17 +54365,23 @@
     method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
     method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
     method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
     method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandles.Lookup lookup();
     method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
     method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
     method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
   }
 
@@ -54287,6 +54398,7 @@
     method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
+    method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
     method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
diff --git a/api/system-current.txt b/api/system-current.txt
index 3b2ad3f..7341424 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -121,6 +121,7 @@
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
     field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
+    field public static final java.lang.String INSTANT_APP_FOREGROUND_SERVICE = "android.permission.INSTANT_APP_FOREGROUND_SERVICE";
     field public static final java.lang.String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
     field public static final java.lang.String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
     field public static final java.lang.String INTERACT_ACROSS_USERS_FULL = "android.permission.INTERACT_ACROSS_USERS_FULL";
@@ -206,6 +207,7 @@
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
     field public static final java.lang.String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+    field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
     field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
     field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
@@ -315,7 +317,6 @@
 
   public static final class R.attr {
     ctor public R.attr();
-    field public static final int __removed0 = 16844097; // 0x1010541
     field public static final int __removed1 = 16844099; // 0x1010543
     field public static final int absListViewStyle = 16842858; // 0x101006a
     field public static final int accessibilityEventTypes = 16843648; // 0x1010380
@@ -381,6 +382,7 @@
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
     field public static final int allowUndo = 16843999; // 0x10104df
     field public static final int alpha = 16843551; // 0x101031f
+    field public static final int alphabeticModifiers = 16844112; // 0x1010550
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
     field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
@@ -1035,6 +1037,7 @@
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
+    field public static final int numericModifiers = 16844113; // 0x1010551
     field public static final int numericShortcut = 16843236; // 0x10101e4
     field public static final int offset = 16844052; // 0x1010514
     field public static final int onClick = 16843375; // 0x101026f
@@ -1386,6 +1389,7 @@
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetName = 16843853; // 0x101044d
     field public static final int targetPackage = 16842785; // 0x1010021
+    field public static final int targetProcess = 16844097; // 0x1010541
     field public static final int targetSandboxVersion = 16844110; // 0x101054e
     field public static final int targetSdkVersion = 16843376; // 0x1010270
     field public static final int taskAffinity = 16842770; // 0x1010012
@@ -2807,11 +2811,25 @@
 
 package android.accessibilityservice {
 
+  public final class AccessibilityButtonController {
+    method public boolean isAccessibilityButtonAvailable();
+    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, android.os.Handler);
+    method public void unregisterAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+  }
+
+  public static abstract class AccessibilityButtonController.AccessibilityButtonCallback {
+    ctor public AccessibilityButtonController.AccessibilityButtonCallback();
+    method public void onAvailabilityChanged(android.accessibilityservice.AccessibilityButtonController, boolean);
+    method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
+  }
+
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
     method public final void disableSelf();
     method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
     method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
@@ -2924,6 +2942,7 @@
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
     field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
     field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
@@ -3028,7 +3047,7 @@
   public class AccountManager {
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
-    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, java.lang.Integer>);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[]);
     method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -3038,7 +3057,7 @@
     method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
-    method public int getAccountVisibility(android.accounts.Account, int);
+    method public int getAccountVisibility(android.accounts.Account, java.lang.String);
     method public android.accounts.Account[] getAccounts();
     method public java.util.Map<android.accounts.Account, java.lang.Integer> getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String);
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -3049,9 +3068,9 @@
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
+    method public java.util.Map<java.lang.String, java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
-    method public java.util.Map<java.lang.Integer, java.lang.Integer> getUidsAndVisibilityForAccount(android.accounts.Account);
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
@@ -3065,7 +3084,7 @@
     method public boolean removeAccountExplicitly(android.accounts.Account);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
     method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
-    method public boolean setAccountVisibility(android.accounts.Account, int, int);
+    method public boolean setAccountVisibility(android.accounts.Account, java.lang.String, int);
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
@@ -3105,8 +3124,8 @@
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
     field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
-    field public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3; // 0xfffffffd
-    field public static final int UID_KEY_DEFAULT_VISIBILITY = -2; // 0xfffffffe
+    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
+    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
     field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
     field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
     field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -4964,6 +4983,7 @@
     method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    method public void addResults(android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnDestroy(android.app.Activity);
@@ -4988,6 +5008,7 @@
     method public android.os.Bundle getBinderCounts();
     method public android.content.ComponentName getComponentName();
     method public android.content.Context getContext();
+    method public java.lang.String getProcessName();
     method public android.content.Context getTargetContext();
     method public android.app.UiAutomation getUiAutomation();
     method public android.app.UiAutomation getUiAutomation(int);
@@ -5204,15 +5225,20 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public int getBadgeIcon();
     method public java.lang.String getChannel();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
     method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
+    method public java.lang.String getShortcutId();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public long getTimeout();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
+    field public static final int BADGE_ICON_LARGE = 2; // 0x2
+    field public static final int BADGE_ICON_NONE = 0; // 0x0
+    field public static final int BADGE_ICON_SMALL = 1; // 0x1
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
     field public static final java.lang.String CATEGORY_CALL = "call";
     field public static final java.lang.String CATEGORY_EMAIL = "email";
@@ -5306,7 +5332,7 @@
     field public deprecated int ledARGB;
     field public deprecated int ledOffMS;
     field public deprecated int ledOnMS;
-    field public deprecated int number;
+    field public int number;
     field public deprecated int priority;
     field public android.app.Notification publicVersion;
     field public deprecated android.net.Uri sound;
@@ -5394,6 +5420,7 @@
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
+    method public android.app.Notification.Builder chooseBadgeIcon(int);
     method public android.widget.RemoteViews createBigContentView();
     method public android.widget.RemoteViews createContentView();
     method public android.widget.RemoteViews createHeadsUpContentView();
@@ -5426,13 +5453,14 @@
     method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
     method public deprecated android.app.Notification.Builder setLights(int, int, int);
     method public android.app.Notification.Builder setLocalOnly(boolean);
-    method public deprecated android.app.Notification.Builder setNumber(int);
+    method public android.app.Notification.Builder setNumber(int);
     method public android.app.Notification.Builder setOngoing(boolean);
     method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
     method public deprecated android.app.Notification.Builder setPriority(int);
     method public android.app.Notification.Builder setProgress(int, int, boolean);
     method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
     method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+    method public android.app.Notification.Builder setShortcutId(java.lang.String);
     method public android.app.Notification.Builder setShowWhen(boolean);
     method public android.app.Notification.Builder setSmallIcon(int);
     method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5623,11 +5651,13 @@
     method public boolean canBypassDnd();
     method public boolean canShowBadge();
     method public int describeContents();
+    method public void enableLights(boolean);
     method public void enableVibration(boolean);
     method public android.media.AudioAttributes getAudioAttributes();
     method public java.lang.String getGroup();
     method public java.lang.String getId();
     method public int getImportance();
+    method public int getLightColor();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
@@ -5640,7 +5670,7 @@
     method public void setDeleted(boolean);
     method public void setGroup(java.lang.String);
     method public void setImportance(int);
-    method public void setLights(boolean);
+    method public void setLightColor(int);
     method public void setLockscreenVisibility(int);
     method public void setShowBadge(boolean);
     method public void setSound(android.net.Uri, android.media.AudioAttributes);
@@ -5849,10 +5879,11 @@
   }
 
   public final class RemoteAction implements android.os.Parcelable {
-    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.RemoteAction clone();
     method public int describeContents();
     method public void dump(java.lang.String, java.io.PrintWriter);
+    method public android.app.PendingIntent getActionIntent();
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getTitle();
@@ -5860,10 +5891,6 @@
     field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
   }
 
-  public static abstract interface RemoteAction.OnActionListener {
-    method public abstract void onAction(android.app.RemoteAction);
-  }
-
   public final class RemoteInput implements android.os.Parcelable {
     method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
@@ -6202,6 +6229,10 @@
     method public void onDetached();
   }
 
+  public class VrManager {
+    method public void setPersistentVrModeEnabled(boolean);
+  }
+
   public final class WallpaperInfo implements android.os.Parcelable {
     ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -6400,6 +6431,7 @@
     method public java.lang.CharSequence getDeviceOwnerOrganizationName();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+    method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
     method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
@@ -8327,6 +8359,65 @@
 
 }
 
+package android.companion {
+
+  public final class AssociationRequest<F extends android.companion.DeviceFilter> implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+  }
+
+  public static final class AssociationRequest.Builder<F extends android.companion.DeviceFilter> {
+    method public android.companion.AssociationRequest<F> build();
+    method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothDeviceFilter> createForBluetoothDevice();
+    method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothLEDeviceFilter> createForBluetoothLEDevice();
+    method public android.companion.AssociationRequest.Builder<F> setDeviceFilter(F);
+    method public android.companion.AssociationRequest.Builder<F> setSingleDevice(boolean);
+  }
+
+  public final class BluetoothDeviceFilter implements android.companion.DeviceFilter {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.BluetoothDeviceFilter> CREATOR;
+  }
+
+  public static final class BluetoothDeviceFilter.Builder {
+    ctor public BluetoothDeviceFilter.Builder();
+    method public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
+    method public android.companion.BluetoothDeviceFilter build();
+    method public android.companion.BluetoothDeviceFilter.Builder setAddress(java.lang.String);
+    method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+  }
+
+  public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+  }
+
+  public static final class BluetoothLEDeviceFilter.Builder {
+    ctor public BluetoothLEDeviceFilter.Builder();
+    method public android.companion.BluetoothLEDeviceFilter build();
+    method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+    method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
+  }
+
+  public final class CompanionDeviceManager {
+    method public void associate(android.companion.AssociationRequest<?>, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
+    field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+  }
+
+  public static abstract class CompanionDeviceManager.Callback {
+    ctor public CompanionDeviceManager.Callback();
+    method public abstract void onDeviceFound(android.content.IntentSender);
+    method public abstract void onFailure(java.lang.CharSequence);
+  }
+
+  public abstract interface DeviceFilter<D extends android.os.Parcelable> implements android.os.Parcelable {
+  }
+
+}
+
 package android.content {
 
   public abstract class AbstractThreadedSyncAdapter {
@@ -8946,6 +9037,7 @@
     field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
     field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
+    field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
     field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
@@ -9004,6 +9096,7 @@
     field public static final java.lang.String USB_SERVICE = "usb";
     field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
+    field public static final java.lang.String VR_SERVICE = "vrmanager";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
     field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
@@ -9502,6 +9595,10 @@
     field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
     field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
     field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+    field public static final java.lang.String EXTRA_AUTO_FILL_ASSIST_STRUCTURE = "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+    field public static final java.lang.String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+    field public static final java.lang.String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+    field public static final java.lang.String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
     field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
     field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
     field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -10358,6 +10455,7 @@
     field public java.lang.String[] splitPublicSourceDirs;
     field public java.lang.String[] splitSourceDirs;
     field public java.lang.String targetPackage;
+    field public java.lang.String targetProcess;
   }
 
   public final class IntentFilterVerificationInfo implements android.os.Parcelable {
@@ -10812,6 +10910,7 @@
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
@@ -21319,6 +21418,11 @@
     field public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
   }
 
+  public abstract class BatchedLocationCallback {
+    ctor public BatchedLocationCallback();
+    method public void onLocationBatch(java.util.List<android.location.Location>);
+  }
+
   public class Criteria implements android.os.Parcelable {
     ctor public Criteria();
     ctor public Criteria(android.location.Criteria);
@@ -21857,14 +21961,17 @@
     method public void clearTestProviderEnabled(java.lang.String);
     method public void clearTestProviderLocation(java.lang.String);
     method public void clearTestProviderStatus(java.lang.String);
+    method public void flushGnssBatch();
     method public java.util.List<java.lang.String> getAllProviders();
     method public java.lang.String getBestProvider(android.location.Criteria, boolean);
+    method public int getGnssBatchSize();
     method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
     method public android.location.Location getLastKnownLocation(java.lang.String);
     method public android.location.LocationProvider getProvider(java.lang.String);
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
+    method public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler);
     method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
@@ -21895,6 +22002,7 @@
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+    method public boolean unregisterGnssBatchedLocationCallback(android.location.BatchedLocationCallback);
     method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatus.Callback);
@@ -21996,6 +22104,7 @@
     method public int getContentType();
     method public int getFlags();
     method public int getUsage();
+    method public static int getVolumeControlStream(android.media.AudioAttributes);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
     field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -23506,6 +23615,7 @@
     method public boolean advance();
     method public long getCachedDuration();
     method public android.media.DrmInitData getDrmInitData();
+    method public android.os.Bundle getMetrics();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -25272,6 +25382,8 @@
 
   public final class MediaController {
     ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
+    method public void addQueueItem(android.media.MediaDescription);
+    method public void addQueueItem(android.media.MediaDescription, int);
     method public void adjustVolume(int, int);
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public android.os.Bundle getExtras();
@@ -25290,6 +25402,8 @@
     method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
+    method public void removeQueueItem(android.media.MediaDescription);
+    method public void removeQueueItemAt(int);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void setVolumeTo(int, int);
     method public void unregisterCallback(android.media.session.MediaController.Callback);
@@ -25367,11 +25481,14 @@
     method public void setSessionActivity(android.app.PendingIntent);
     method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
   public static abstract class MediaSession.Callback {
     ctor public MediaSession.Callback();
+    method public void onAddQueueItem(android.media.MediaDescription);
+    method public void onAddQueueItem(android.media.MediaDescription, int);
     method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void onCustomAction(java.lang.String, android.os.Bundle);
     method public void onFastForward();
@@ -25385,6 +25502,8 @@
     method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
     method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
     method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+    method public void onRemoveQueueItem(android.media.MediaDescription);
+    method public void onRemoveQueueItemAt(int);
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
@@ -25601,6 +25720,31 @@
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
+  public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+  }
+
   public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
     field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
   }
@@ -25687,7 +25831,7 @@
     field public static final java.lang.String CONTENT_DIRECTORY = "logo";
   }
 
-  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
+  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
     field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
     field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
     field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
@@ -25696,54 +25840,32 @@
     field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
     field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
     field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_AUTHOR = "author";
     field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
     field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
     field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
     field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
     field public static final java.lang.String COLUMN_LIVE = "live";
     field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
     field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
     field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
     field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
     field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
     field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
     field public static final java.lang.String COLUMN_WEIGHT = "weight";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
@@ -25799,37 +25921,15 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
-  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
     field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
     field public static final android.net.Uri CONTENT_URI;
@@ -28105,7 +28205,7 @@
     field public int numScorerOverride;
     field public int numScorerOverrideAndSwitchedNetwork;
     field public java.lang.String preSharedKey;
-    field public int priority;
+    field public deprecated int priority;
     field public java.lang.String providerFriendlyName;
     field public long[] roamingConsortiumIds;
     field public int status;
@@ -28227,11 +28327,14 @@
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
+    field public static final int AKA = 6; // 0x6
+    field public static final int AKA_PRIME = 7; // 0x7
     field public static final int GTC = 4; // 0x4
     field public static final int MSCHAP = 2; // 0x2
     field public static final int MSCHAPV2 = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int PAP = 1; // 0x1
+    field public static final int SIM = 5; // 0x5
   }
 
   public class WifiInfo implements android.os.Parcelable {
@@ -28289,13 +28392,13 @@
     method public boolean isWifiApEnabled();
     method public boolean isWifiEnabled();
     method public boolean isWifiScannerSupported();
-    method public boolean pingSupplicant();
+    method public deprecated boolean pingSupplicant();
     method public void queryPasspointIcon(long, java.lang.String);
     method public boolean reassociate();
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean removePasspointConfiguration(java.lang.String);
-    method public boolean saveConfiguration();
+    method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -28697,7 +28800,7 @@
     method public java.lang.String getSubscriptionType();
     method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
     method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
-    method public int getUpdateIdentififer();
+    method public int getUpdateIdentifier();
     method public long getUsageLimitDataLimit();
     method public long getUsageLimitStartTimeInMs();
     method public long getUsageLimitTimeLimitInMinutes();
@@ -28739,7 +28842,7 @@
     method public int describeContents();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
-    method public boolean getCheckAaaServerStatus();
+    method public boolean getCheckAaaServerCertStatus();
     method public java.security.cert.X509Certificate[] getClientCertificateChain();
     method public java.security.PrivateKey getClientPrivateKey();
     method public long getCreationTimeInMs();
@@ -28820,7 +28923,7 @@
     method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
     method public java.lang.String getIconUrl();
     method public long[] getMatchAllOis();
-    method public long[] getMatchAnysOis();
+    method public long[] getMatchAnyOis();
     method public java.lang.String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(java.lang.String);
@@ -28842,7 +28945,7 @@
     method public int describeContents();
     method public java.lang.String[] getExcludedSsidList();
     method public int getMaximumBssLoadValue();
-    method public long getMinHomeDownlinkBandWidht();
+    method public long getMinHomeDownlinkBandwidth();
     method public long getMinHomeUplinkBandwidth();
     method public long getMinRoamingDownlinkBandwidth();
     method public long getMinRoamingUplinkBandwidth();
@@ -32467,6 +32570,7 @@
     field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
     field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
     field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
+    field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
     field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
     field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
     field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -39125,26 +39229,19 @@
     ctor public AutoFillService();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
-    method public void onDatasetAuthenticationRequest(android.os.Bundle, int);
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
-    method public void onFillResponseAuthenticationRequest(android.os.Bundle, int);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
-    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
-    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
-    field public static final int FLAG_AUTHENTICATION_ERROR = 4; // 0x4
-    field public static final int FLAG_AUTHENTICATION_REQUESTED = 1; // 0x1
-    field public static final int FLAG_AUTHENTICATION_SUCCESS = 2; // 0x2
-    field public static final int FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE = 8; // 0x8
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
-  public final class FillCallback {
-    method public void onDatasetAuthentication(android.view.autofill.Dataset, int);
+  public final class FillCallback implements android.os.Parcelable {
+    method public int describeContents();
     method public void onFailure(java.lang.CharSequence);
-    method public void onFillResponseAuthentication(int);
     method public void onSuccess(android.view.autofill.FillResponse);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.FillCallback> CREATOR;
   }
 
   public final class SaveCallback {
@@ -39762,6 +39859,7 @@
     method public boolean onKeyUp(int, android.view.KeyEvent);
     method public void onLockscreenShown();
     method public void onLowMemory();
+    method public void onPrepareShow(android.os.Bundle, int);
     method public void onRequestAbortVoice(android.service.voice.VoiceInteractionSession.AbortVoiceRequest);
     method public void onRequestCommand(android.service.voice.VoiceInteractionSession.CommandRequest);
     method public void onRequestCompleteVoice(android.service.voice.VoiceInteractionSession.CompleteVoiceRequest);
@@ -39775,6 +39873,7 @@
     method public void setDisabledShowContext(int);
     method public void setKeepAwake(boolean);
     method public void setTheme(int);
+    method public void setUiEnabled(boolean);
     method public void show(android.os.Bundle, int);
     method public void startVoiceActivity(android.content.Intent);
     field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
@@ -45350,6 +45449,15 @@
     method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
   }
 
+  public abstract class TransitionListenerAdapter implements android.transition.Transition.TransitionListener {
+    ctor public TransitionListenerAdapter();
+    method public void onTransitionCancel(android.transition.Transition);
+    method public void onTransitionEnd(android.transition.Transition);
+    method public void onTransitionPause(android.transition.Transition);
+    method public void onTransitionResume(android.transition.Transition);
+    method public void onTransitionStart(android.transition.Transition);
+  }
+
   public class TransitionManager {
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -47132,6 +47240,7 @@
     field public static final int FLAG_APPEND_TO_GROUP = 1; // 0x1
     field public static final int FLAG_PERFORM_NO_CLOSE = 1; // 0x1
     field public static final int NONE = 0; // 0x0
+    field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f
   }
 
   public class MenuInflater {
@@ -47144,6 +47253,7 @@
     method public abstract boolean expandActionView();
     method public abstract android.view.ActionProvider getActionProvider();
     method public abstract android.view.View getActionView();
+    method public default int getAlphabeticModifiers();
     method public abstract char getAlphabeticShortcut();
     method public default java.lang.CharSequence getContentDescription();
     method public abstract int getGroupId();
@@ -47151,6 +47261,7 @@
     method public abstract android.content.Intent getIntent();
     method public abstract int getItemId();
     method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
+    method public default int getNumericModifiers();
     method public abstract char getNumericShortcut();
     method public abstract int getOrder();
     method public abstract android.view.SubMenu getSubMenu();
@@ -47167,6 +47278,7 @@
     method public abstract android.view.MenuItem setActionView(android.view.View);
     method public abstract android.view.MenuItem setActionView(int);
     method public abstract android.view.MenuItem setAlphabeticShortcut(char);
+    method public default android.view.MenuItem setAlphabeticShortcut(char, int);
     method public abstract android.view.MenuItem setCheckable(boolean);
     method public abstract android.view.MenuItem setChecked(boolean);
     method public default android.view.MenuItem setContentDescription(java.lang.CharSequence);
@@ -47175,9 +47287,11 @@
     method public abstract android.view.MenuItem setIcon(int);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
+    method public default android.view.MenuItem setNumericShortcut(char, int);
     method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
     method public abstract android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener);
     method public abstract android.view.MenuItem setShortcut(char, char);
+    method public default android.view.MenuItem setShortcut(char, char, int, int);
     method public abstract void setShowAsAction(int);
     method public abstract android.view.MenuItem setShowAsActionFlags(int);
     method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
@@ -47667,6 +47781,7 @@
     ctor public View(android.content.Context, android.util.AttributeSet, int);
     ctor public View(android.content.Context, android.util.AttributeSet, int, int);
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
+    method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
     method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
@@ -47676,6 +47791,7 @@
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
     method public void autoFill(android.view.autofill.AutoFillValue);
+    method public void autoFillVirtual(int, android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -47749,8 +47865,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final <T extends android.view.View> T findViewById(int);
-    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
+    method public final android.view.View findViewById(int);
+    method public final android.view.View findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
@@ -47766,7 +47882,7 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.view.autofill.AutoFillType getAutoFillType();
-    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
+    method public android.view.autofill.AutoFillValue getAutoFillValue();
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -47904,6 +48020,7 @@
     method public float getX();
     method public float getY();
     method public float getZ();
+    method public boolean hasExplicitFocusable();
     method public boolean hasFocus();
     method public boolean hasFocusable();
     method public boolean hasNestedScrollingParent();
@@ -48064,7 +48181,7 @@
     method public final void requestUnbufferedDispatch(android.view.MotionEvent);
     method public static int resolveSize(int, int);
     method public static int resolveSizeAndState(int, int, int);
-    method public boolean restoreDefaultFocus(int);
+    method public boolean restoreDefaultFocus();
     method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -48361,6 +48478,7 @@
 
   public static class View.AccessibilityDelegate {
     ctor public View.AccessibilityDelegate();
+    method public void addExtraDataToAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
     method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
@@ -49484,6 +49602,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
     method public deprecated int getActions();
+    method public java.util.List<java.lang.String> getAvailableExtraData();
     method public void getBoundsInParent(android.graphics.Rect);
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -49540,11 +49659,13 @@
     method public boolean performAction(int, android.os.Bundle);
     method public void recycle();
     method public boolean refresh();
+    method public boolean refreshWithExtraData(java.lang.String, android.os.Bundle);
     method public deprecated void removeAction(int);
     method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
     method public boolean removeChild(android.view.View);
     method public boolean removeChild(android.view.View, int);
     method public void setAccessibilityFocused(boolean);
+    method public void setAvailableExtraData(java.util.List<java.lang.String>);
     method public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
     method public void setCanOpenPopup(boolean);
@@ -49627,6 +49748,9 @@
     field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
     field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
     field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
     field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
     field public static final int FOCUS_INPUT = 1; // 0x1
     field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
@@ -49708,6 +49832,7 @@
 
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
+    method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -50118,11 +50243,11 @@
   }
 
   public final class AutoFillManager {
-    method public void onValueChanged(android.view.View, android.view.autofill.AutoFillValue);
-    method public void updateAutoFillInput(android.view.View, int);
-    method public void updateAutoFillInput(android.view.View, int, android.graphics.Rect, int);
-    field public static final int FLAG_UPDATE_UI_HIDE = 2; // 0x2
-    field public static final int FLAG_UPDATE_UI_SHOW = 1; // 0x1
+    method public void focusChanged(android.view.View, boolean);
+    method public void reset();
+    method public void valueChanged(android.view.View);
+    method public void virtualFocusChanged(android.view.View, int, android.graphics.Rect, boolean);
+    method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
   }
 
   public final class AutoFillType implements android.os.Parcelable {
@@ -50157,10 +50282,9 @@
   }
 
   public static final class Dataset.Builder {
-    ctor public Dataset.Builder(java.lang.CharSequence);
+    ctor public Dataset.Builder(java.lang.String, java.lang.CharSequence);
     method public android.view.autofill.Dataset build();
-    method public android.view.autofill.Dataset.Builder requiresCustomAuthentication(android.os.Bundle, int);
-    method public android.view.autofill.Dataset.Builder requiresFingerprintAuthentication(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.Bundle, int);
+    method public android.view.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
     method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
     method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
   }
@@ -50172,27 +50296,14 @@
   }
 
   public static final class FillResponse.Builder {
-    ctor public FillResponse.Builder();
+    ctor public FillResponse.Builder(java.lang.String);
     method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
     method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
     method public android.view.autofill.FillResponse build();
-    method public android.view.autofill.FillResponse.Builder requiresCustomAuthentication(android.os.Bundle, int);
-    method public android.view.autofill.FillResponse.Builder requiresFingerprintAuthentication(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.Bundle, int);
+    method public android.view.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender);
     method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
   }
 
-  public abstract class VirtualViewDelegate {
-    ctor public VirtualViewDelegate();
-    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
-  }
-
-  public static abstract class VirtualViewDelegate.Callback {
-    ctor public VirtualViewDelegate.Callback();
-    method public void onAutoFillInputUpdated(int, android.graphics.Rect, int);
-    method public void onNodeRemoved(int...);
-    method public void onValueChanged(int);
-  }
-
 }
 
 package android.view.inputmethod {
@@ -54049,6 +54160,7 @@
     method public int getAutoSizeMaxTextSize();
     method public int getAutoSizeMinTextSize();
     method public int getAutoSizeStepGranularity();
+    method public int[] getAutoSizeTextPresetSizes();
     method public int getAutoSizeTextType();
     method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
@@ -54162,6 +54274,7 @@
     method public void setAutoSizeMaxTextSize(int, float);
     method public void setAutoSizeMinTextSize(int, float);
     method public void setAutoSizeStepGranularity(int, float);
+    method public void setAutoSizeTextPresetSizes(int[]);
     method public void setAutoSizeTextType(int);
     method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
@@ -54295,6 +54408,7 @@
     method public void setIs24HourView(java.lang.Boolean);
     method public void setMinute(int);
     method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+    method public boolean validateInput();
   }
 
   public static abstract interface TimePicker.OnTimeChangedListener {
@@ -54693,6 +54807,8 @@
     field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
     field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
     field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+    field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+    field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
     field public static final int OP_INVOKE_STATIC = 113; // 0x71
     field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
     field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -57987,12 +58103,15 @@
   }
 
   public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
     method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
     method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
     method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
     method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
     method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
     method public boolean isVarargsCollector();
     method public java.lang.invoke.MethodType type();
@@ -58026,17 +58145,23 @@
     method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
     method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
     method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
     method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandles.Lookup lookup();
     method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
     method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
     method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
   }
 
@@ -58053,6 +58178,7 @@
     method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
+    method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
     method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
diff --git a/api/test-current.txt b/api/test-current.txt
index bfb0d14..4988ab3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -79,6 +79,7 @@
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
     field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
+    field public static final java.lang.String INSTANT_APP_FOREGROUND_SERVICE = "android.permission.INSTANT_APP_FOREGROUND_SERVICE";
     field public static final java.lang.String INTERNET = "android.permission.INTERNET";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
@@ -118,6 +119,7 @@
     field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+    field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -203,7 +205,6 @@
 
   public static final class R.attr {
     ctor public R.attr();
-    field public static final int __removed0 = 16844097; // 0x1010541
     field public static final int __removed1 = 16844099; // 0x1010543
     field public static final int absListViewStyle = 16842858; // 0x101006a
     field public static final int accessibilityEventTypes = 16843648; // 0x1010380
@@ -269,6 +270,7 @@
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
     field public static final int allowUndo = 16843999; // 0x10104df
     field public static final int alpha = 16843551; // 0x101031f
+    field public static final int alphabeticModifiers = 16844112; // 0x1010550
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
     field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
@@ -923,6 +925,7 @@
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
+    field public static final int numericModifiers = 16844113; // 0x1010551
     field public static final int numericShortcut = 16843236; // 0x10101e4
     field public static final int offset = 16844052; // 0x1010514
     field public static final int onClick = 16843375; // 0x101026f
@@ -1270,6 +1273,7 @@
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetName = 16843853; // 0x101044d
     field public static final int targetPackage = 16842785; // 0x1010021
+    field public static final int targetProcess = 16844097; // 0x1010541
     field public static final int targetSandboxVersion = 16844110; // 0x101054e
     field public static final int targetSdkVersion = 16843376; // 0x1010270
     field public static final int taskAffinity = 16842770; // 0x1010012
@@ -2688,11 +2692,25 @@
 
 package android.accessibilityservice {
 
+  public final class AccessibilityButtonController {
+    method public boolean isAccessibilityButtonAvailable();
+    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, android.os.Handler);
+    method public void unregisterAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+  }
+
+  public static abstract class AccessibilityButtonController.AccessibilityButtonCallback {
+    ctor public AccessibilityButtonController.AccessibilityButtonCallback();
+    method public void onAvailabilityChanged(android.accessibilityservice.AccessibilityButtonController, boolean);
+    method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
+  }
+
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
     method public final void disableSelf();
     method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
     method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
@@ -2805,6 +2823,7 @@
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
     field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
     field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
@@ -2909,7 +2928,7 @@
   public class AccountManager {
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
-    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, java.lang.Integer>);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[]);
     method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -2918,7 +2937,7 @@
     method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
-    method public int getAccountVisibility(android.accounts.Account, int);
+    method public int getAccountVisibility(android.accounts.Account, java.lang.String);
     method public android.accounts.Account[] getAccounts();
     method public java.util.Map<android.accounts.Account, java.lang.Integer> getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String);
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2929,9 +2948,9 @@
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
+    method public java.util.Map<java.lang.String, java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
-    method public java.util.Map<java.lang.Integer, java.lang.Integer> getUidsAndVisibilityForAccount(android.accounts.Account);
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
@@ -2945,7 +2964,7 @@
     method public boolean removeAccountExplicitly(android.accounts.Account);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
     method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
-    method public boolean setAccountVisibility(android.accounts.Account, int, int);
+    method public boolean setAccountVisibility(android.accounts.Account, java.lang.String, int);
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
@@ -2985,8 +3004,8 @@
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
     field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
-    field public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3; // 0xfffffffd
-    field public static final int UID_KEY_DEFAULT_VISIBILITY = -2; // 0xfffffffe
+    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.key_legacy_not_visible";
+    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.key_legacy_visible";
     field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
     field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
     field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -4814,6 +4833,7 @@
     method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    method public void addResults(android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnDestroy(android.app.Activity);
@@ -4838,6 +4858,7 @@
     method public android.os.Bundle getBinderCounts();
     method public android.content.ComponentName getComponentName();
     method public android.content.Context getContext();
+    method public java.lang.String getProcessName();
     method public android.content.Context getTargetContext();
     method public android.app.UiAutomation getUiAutomation();
     method public android.app.UiAutomation getUiAutomation(int);
@@ -5054,14 +5075,19 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public int getBadgeIcon();
     method public java.lang.String getChannel();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
+    method public java.lang.String getShortcutId();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public long getTimeout();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
+    field public static final int BADGE_ICON_LARGE = 2; // 0x2
+    field public static final int BADGE_ICON_NONE = 0; // 0x0
+    field public static final int BADGE_ICON_SMALL = 1; // 0x1
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
     field public static final java.lang.String CATEGORY_CALL = "call";
     field public static final java.lang.String CATEGORY_EMAIL = "email";
@@ -5153,7 +5179,7 @@
     field public deprecated int ledARGB;
     field public deprecated int ledOffMS;
     field public deprecated int ledOnMS;
-    field public deprecated int number;
+    field public int number;
     field public deprecated int priority;
     field public android.app.Notification publicVersion;
     field public deprecated android.net.Uri sound;
@@ -5241,6 +5267,7 @@
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
+    method public android.app.Notification.Builder chooseBadgeIcon(int);
     method public android.widget.RemoteViews createBigContentView();
     method public android.widget.RemoteViews createContentView();
     method public android.widget.RemoteViews createHeadsUpContentView();
@@ -5273,13 +5300,14 @@
     method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
     method public deprecated android.app.Notification.Builder setLights(int, int, int);
     method public android.app.Notification.Builder setLocalOnly(boolean);
-    method public deprecated android.app.Notification.Builder setNumber(int);
+    method public android.app.Notification.Builder setNumber(int);
     method public android.app.Notification.Builder setOngoing(boolean);
     method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
     method public deprecated android.app.Notification.Builder setPriority(int);
     method public android.app.Notification.Builder setProgress(int, int, boolean);
     method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
     method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
+    method public android.app.Notification.Builder setShortcutId(java.lang.String);
     method public android.app.Notification.Builder setShowWhen(boolean);
     method public android.app.Notification.Builder setSmallIcon(int);
     method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5457,11 +5485,13 @@
     method public boolean canBypassDnd();
     method public boolean canShowBadge();
     method public int describeContents();
+    method public void enableLights(boolean);
     method public void enableVibration(boolean);
     method public android.media.AudioAttributes getAudioAttributes();
     method public java.lang.String getGroup();
     method public java.lang.String getId();
     method public int getImportance();
+    method public int getLightColor();
     method public int getLockscreenVisibility();
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
@@ -5469,7 +5499,7 @@
     method public void setBypassDnd(boolean);
     method public void setGroup(java.lang.String);
     method public void setImportance(int);
-    method public void setLights(boolean);
+    method public void setLightColor(int);
     method public void setLockscreenVisibility(int);
     method public void setShowBadge(boolean);
     method public void setSound(android.net.Uri, android.media.AudioAttributes);
@@ -5664,10 +5694,11 @@
   }
 
   public final class RemoteAction implements android.os.Parcelable {
-    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
+    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.RemoteAction clone();
     method public int describeContents();
     method public void dump(java.lang.String, java.io.PrintWriter);
+    method public android.app.PendingIntent getActionIntent();
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getTitle();
@@ -5675,10 +5706,6 @@
     field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR;
   }
 
-  public static abstract interface RemoteAction.OnActionListener {
-    method public abstract void onAction(android.app.RemoteAction);
-  }
-
   public final class RemoteInput implements android.os.Parcelable {
     method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
@@ -6214,6 +6241,7 @@
     method public long getLastBugReportRequestTime();
     method public long getLastNetworkLogRetrievalTime();
     method public long getLastSecurityLogRetrievalTime();
+    method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
     method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
@@ -7964,6 +7992,65 @@
 
 }
 
+package android.companion {
+
+  public final class AssociationRequest<F extends android.companion.DeviceFilter> implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+  }
+
+  public static final class AssociationRequest.Builder<F extends android.companion.DeviceFilter> {
+    method public android.companion.AssociationRequest<F> build();
+    method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothDeviceFilter> createForBluetoothDevice();
+    method public static android.companion.AssociationRequest.Builder<android.companion.BluetoothLEDeviceFilter> createForBluetoothLEDevice();
+    method public android.companion.AssociationRequest.Builder<F> setDeviceFilter(F);
+    method public android.companion.AssociationRequest.Builder<F> setSingleDevice(boolean);
+  }
+
+  public final class BluetoothDeviceFilter implements android.companion.DeviceFilter {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.BluetoothDeviceFilter> CREATOR;
+  }
+
+  public static final class BluetoothDeviceFilter.Builder {
+    ctor public BluetoothDeviceFilter.Builder();
+    method public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
+    method public android.companion.BluetoothDeviceFilter build();
+    method public android.companion.BluetoothDeviceFilter.Builder setAddress(java.lang.String);
+    method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+  }
+
+  public final class BluetoothLEDeviceFilter implements android.companion.DeviceFilter {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.companion.BluetoothLEDeviceFilter> CREATOR;
+  }
+
+  public static final class BluetoothLEDeviceFilter.Builder {
+    ctor public BluetoothLEDeviceFilter.Builder();
+    method public android.companion.BluetoothLEDeviceFilter build();
+    method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+    method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
+  }
+
+  public final class CompanionDeviceManager {
+    method public void associate(android.companion.AssociationRequest<?>, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
+    field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+  }
+
+  public static abstract class CompanionDeviceManager.Callback {
+    ctor public CompanionDeviceManager.Callback();
+    method public abstract void onDeviceFound(android.content.IntentSender);
+    method public abstract void onFailure(java.lang.CharSequence);
+  }
+
+  public abstract interface DeviceFilter<D extends android.os.Parcelable> implements android.os.Parcelable {
+  }
+
+}
+
 package android.content {
 
   public abstract class AbstractThreadedSyncAdapter {
@@ -8578,6 +8665,7 @@
     field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
     field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
+    field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -9116,6 +9204,10 @@
     field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
     field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
     field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+    field public static final java.lang.String EXTRA_AUTO_FILL_ASSIST_STRUCTURE = "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+    field public static final java.lang.String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+    field public static final java.lang.String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+    field public static final java.lang.String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
     field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
     field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
     field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -9931,6 +10023,7 @@
     field public java.lang.String[] splitPublicSourceDirs;
     field public java.lang.String[] splitSourceDirs;
     field public java.lang.String targetPackage;
+    field public java.lang.String targetProcess;
   }
 
   public class LabeledIntent extends android.content.Intent {
@@ -10356,6 +10449,7 @@
     field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
     field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
     field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
     field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
@@ -20532,6 +20626,7 @@
     method public int getContentType();
     method public int getFlags();
     method public int getUsage();
+    method public static int getVolumeControlStream(android.media.AudioAttributes);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
     field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -21992,6 +22087,7 @@
     method public boolean advance();
     method public long getCachedDuration();
     method public android.media.DrmInitData getDrmInitData();
+    method public android.os.Bundle getMetrics();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -23675,6 +23771,8 @@
 
   public final class MediaController {
     ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
+    method public void addQueueItem(android.media.MediaDescription);
+    method public void addQueueItem(android.media.MediaDescription, int);
     method public void adjustVolume(int, int);
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public android.os.Bundle getExtras();
@@ -23693,6 +23791,8 @@
     method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
+    method public void removeQueueItem(android.media.MediaDescription);
+    method public void removeQueueItemAt(int);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void setVolumeTo(int, int);
     method public void unregisterCallback(android.media.session.MediaController.Callback);
@@ -23770,11 +23870,14 @@
     method public void setSessionActivity(android.app.PendingIntent);
     method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
   public static abstract class MediaSession.Callback {
     ctor public MediaSession.Callback();
+    method public void onAddQueueItem(android.media.MediaDescription);
+    method public void onAddQueueItem(android.media.MediaDescription, int);
     method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
     method public void onCustomAction(java.lang.String, android.os.Bundle);
     method public void onFastForward();
@@ -23788,6 +23891,8 @@
     method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
     method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
     method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+    method public void onRemoveQueueItem(android.media.MediaDescription);
+    method public void onRemoveQueueItemAt(int);
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
@@ -23945,6 +24050,31 @@
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
+  public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
+    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+  }
+
   public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
     field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
   }
@@ -24027,7 +24157,7 @@
     field public static final java.lang.String CONTENT_DIRECTORY = "logo";
   }
 
-  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
+  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
     field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
     field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
     field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
@@ -24036,53 +24166,31 @@
     field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
     field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
     field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final java.lang.String COLUMN_AUTHOR = "author";
     field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
     field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
     field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
     field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
     field public static final java.lang.String COLUMN_LIVE = "live";
     field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
     field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
     field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
     field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
     field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
     field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
     field public static final java.lang.String COLUMN_WEIGHT = "weight";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
@@ -24138,37 +24246,15 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
-  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
     field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
     field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
     field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
     field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
     field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
     field public static final android.net.Uri CONTENT_URI;
@@ -25698,7 +25784,7 @@
     field public boolean isHomeProviderNetwork;
     field public int networkId;
     field public java.lang.String preSharedKey;
-    field public int priority;
+    field public deprecated int priority;
     field public java.lang.String providerFriendlyName;
     field public long[] roamingConsortiumIds;
     field public int status;
@@ -25803,11 +25889,14 @@
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
+    field public static final int AKA = 6; // 0x6
+    field public static final int AKA_PRIME = 7; // 0x7
     field public static final int GTC = 4; // 0x4
     field public static final int MSCHAP = 2; // 0x2
     field public static final int MSCHAPV2 = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int PAP = 1; // 0x1
+    field public static final int SIM = 5; // 0x5
   }
 
   public class WifiInfo implements android.os.Parcelable {
@@ -25854,13 +25943,13 @@
     method public boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
     method public boolean isWifiEnabled();
-    method public boolean pingSupplicant();
+    method public deprecated boolean pingSupplicant();
     method public void queryPasspointIcon(long, java.lang.String);
     method public boolean reassociate();
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean removePasspointConfiguration(java.lang.String);
-    method public boolean saveConfiguration();
+    method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -26093,7 +26182,7 @@
     method public java.lang.String getSubscriptionType();
     method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
     method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
-    method public int getUpdateIdentififer();
+    method public int getUpdateIdentifier();
     method public long getUsageLimitDataLimit();
     method public long getUsageLimitStartTimeInMs();
     method public long getUsageLimitTimeLimitInMinutes();
@@ -26135,7 +26224,7 @@
     method public int describeContents();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
-    method public boolean getCheckAaaServerStatus();
+    method public boolean getCheckAaaServerCertStatus();
     method public java.security.cert.X509Certificate[] getClientCertificateChain();
     method public java.security.PrivateKey getClientPrivateKey();
     method public long getCreationTimeInMs();
@@ -26216,7 +26305,7 @@
     method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
     method public java.lang.String getIconUrl();
     method public long[] getMatchAllOis();
-    method public long[] getMatchAnysOis();
+    method public long[] getMatchAnyOis();
     method public java.lang.String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(java.lang.String);
@@ -26238,7 +26327,7 @@
     method public int describeContents();
     method public java.lang.String[] getExcludedSsidList();
     method public int getMaximumBssLoadValue();
-    method public long getMinHomeDownlinkBandWidht();
+    method public long getMinHomeDownlinkBandwidth();
     method public long getMinHomeUplinkBandwidth();
     method public long getMinRoamingDownlinkBandwidth();
     method public long getMinRoamingUplinkBandwidth();
@@ -29850,6 +29939,7 @@
     field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
     field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
     field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
+    field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
     field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
     field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
     field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -36228,26 +36318,19 @@
     ctor public AutoFillService();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
-    method public void onDatasetAuthenticationRequest(android.os.Bundle, int);
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
-    method public void onFillResponseAuthenticationRequest(android.os.Bundle, int);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
-    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
-    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
-    field public static final int FLAG_AUTHENTICATION_ERROR = 4; // 0x4
-    field public static final int FLAG_AUTHENTICATION_REQUESTED = 1; // 0x1
-    field public static final int FLAG_AUTHENTICATION_SUCCESS = 2; // 0x2
-    field public static final int FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE = 8; // 0x8
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
-  public final class FillCallback {
-    method public void onDatasetAuthentication(android.view.autofill.Dataset, int);
+  public final class FillCallback implements android.os.Parcelable {
+    method public int describeContents();
     method public void onFailure(java.lang.CharSequence);
-    method public void onFillResponseAuthentication(int);
     method public void onSuccess(android.view.autofill.FillResponse);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.FillCallback> CREATOR;
   }
 
   public final class SaveCallback {
@@ -36813,6 +36896,7 @@
     method public boolean onKeyUp(int, android.view.KeyEvent);
     method public void onLockscreenShown();
     method public void onLowMemory();
+    method public void onPrepareShow(android.os.Bundle, int);
     method public void onRequestAbortVoice(android.service.voice.VoiceInteractionSession.AbortVoiceRequest);
     method public void onRequestCommand(android.service.voice.VoiceInteractionSession.CommandRequest);
     method public void onRequestCompleteVoice(android.service.voice.VoiceInteractionSession.CompleteVoiceRequest);
@@ -36826,6 +36910,7 @@
     method public void setDisabledShowContext(int);
     method public void setKeepAwake(boolean);
     method public void setTheme(int);
+    method public void setUiEnabled(boolean);
     method public void show(android.os.Bundle, int);
     method public void startVoiceActivity(android.content.Intent);
     field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
@@ -42088,6 +42173,15 @@
     method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
   }
 
+  public abstract class TransitionListenerAdapter implements android.transition.Transition.TransitionListener {
+    ctor public TransitionListenerAdapter();
+    method public void onTransitionCancel(android.transition.Transition);
+    method public void onTransitionEnd(android.transition.Transition);
+    method public void onTransitionPause(android.transition.Transition);
+    method public void onTransitionResume(android.transition.Transition);
+    method public void onTransitionStart(android.transition.Transition);
+  }
+
   public class TransitionManager {
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
@@ -44034,6 +44128,7 @@
     field public static final int FLAG_APPEND_TO_GROUP = 1; // 0x1
     field public static final int FLAG_PERFORM_NO_CLOSE = 1; // 0x1
     field public static final int NONE = 0; // 0x0
+    field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f
   }
 
   public class MenuInflater {
@@ -44046,6 +44141,7 @@
     method public abstract boolean expandActionView();
     method public abstract android.view.ActionProvider getActionProvider();
     method public abstract android.view.View getActionView();
+    method public default int getAlphabeticModifiers();
     method public abstract char getAlphabeticShortcut();
     method public default java.lang.CharSequence getContentDescription();
     method public abstract int getGroupId();
@@ -44053,6 +44149,7 @@
     method public abstract android.content.Intent getIntent();
     method public abstract int getItemId();
     method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
+    method public default int getNumericModifiers();
     method public abstract char getNumericShortcut();
     method public abstract int getOrder();
     method public abstract android.view.SubMenu getSubMenu();
@@ -44069,6 +44166,7 @@
     method public abstract android.view.MenuItem setActionView(android.view.View);
     method public abstract android.view.MenuItem setActionView(int);
     method public abstract android.view.MenuItem setAlphabeticShortcut(char);
+    method public default android.view.MenuItem setAlphabeticShortcut(char, int);
     method public abstract android.view.MenuItem setCheckable(boolean);
     method public abstract android.view.MenuItem setChecked(boolean);
     method public default android.view.MenuItem setContentDescription(java.lang.CharSequence);
@@ -44077,9 +44175,11 @@
     method public abstract android.view.MenuItem setIcon(int);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
+    method public default android.view.MenuItem setNumericShortcut(char, int);
     method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
     method public abstract android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener);
     method public abstract android.view.MenuItem setShortcut(char, char);
+    method public default android.view.MenuItem setShortcut(char, char, int, int);
     method public abstract void setShowAsAction(int);
     method public abstract android.view.MenuItem setShowAsActionFlags(int);
     method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
@@ -44571,6 +44671,7 @@
     ctor public View(android.content.Context, android.util.AttributeSet, int);
     ctor public View(android.content.Context, android.util.AttributeSet, int, int);
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
+    method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
     method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
@@ -44580,6 +44681,7 @@
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
     method public void autoFill(android.view.autofill.AutoFillValue);
+    method public void autoFillVirtual(int, android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -44653,8 +44755,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final <T extends android.view.View> T findViewById(int);
-    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
+    method public final android.view.View findViewById(int);
+    method public final android.view.View findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
@@ -44670,7 +44772,7 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.view.autofill.AutoFillType getAutoFillType();
-    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
+    method public android.view.autofill.AutoFillValue getAutoFillValue();
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -44809,6 +44911,7 @@
     method public float getX();
     method public float getY();
     method public float getZ();
+    method public boolean hasExplicitFocusable();
     method public boolean hasFocus();
     method public boolean hasFocusable();
     method public boolean hasNestedScrollingParent();
@@ -44969,7 +45072,7 @@
     method public final void requestUnbufferedDispatch(android.view.MotionEvent);
     method public static int resolveSize(int, int);
     method public static int resolveSizeAndState(int, int, int);
-    method public boolean restoreDefaultFocus(int);
+    method public boolean restoreDefaultFocus();
     method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -45266,6 +45369,7 @@
 
   public static class View.AccessibilityDelegate {
     ctor public View.AccessibilityDelegate();
+    method public void addExtraDataToAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
     method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
@@ -46390,6 +46494,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
     method public deprecated int getActions();
+    method public java.util.List<java.lang.String> getAvailableExtraData();
     method public void getBoundsInParent(android.graphics.Rect);
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -46446,11 +46551,13 @@
     method public boolean performAction(int, android.os.Bundle);
     method public void recycle();
     method public boolean refresh();
+    method public boolean refreshWithExtraData(java.lang.String, android.os.Bundle);
     method public deprecated void removeAction(int);
     method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
     method public boolean removeChild(android.view.View);
     method public boolean removeChild(android.view.View, int);
     method public void setAccessibilityFocused(boolean);
+    method public void setAvailableExtraData(java.util.List<java.lang.String>);
     method public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
     method public void setCanOpenPopup(boolean);
@@ -46534,6 +46641,9 @@
     field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
     field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
     field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
     field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
     field public static final int FOCUS_INPUT = 1; // 0x1
     field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
@@ -46615,6 +46725,7 @@
 
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
+    method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -47026,11 +47137,11 @@
   }
 
   public final class AutoFillManager {
-    method public void onValueChanged(android.view.View, android.view.autofill.AutoFillValue);
-    method public void updateAutoFillInput(android.view.View, int);
-    method public void updateAutoFillInput(android.view.View, int, android.graphics.Rect, int);
-    field public static final int FLAG_UPDATE_UI_HIDE = 2; // 0x2
-    field public static final int FLAG_UPDATE_UI_SHOW = 1; // 0x1
+    method public void focusChanged(android.view.View, boolean);
+    method public void reset();
+    method public void valueChanged(android.view.View);
+    method public void virtualFocusChanged(android.view.View, int, android.graphics.Rect, boolean);
+    method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
   }
 
   public final class AutoFillType implements android.os.Parcelable {
@@ -47065,10 +47176,9 @@
   }
 
   public static final class Dataset.Builder {
-    ctor public Dataset.Builder(java.lang.CharSequence);
+    ctor public Dataset.Builder(java.lang.String, java.lang.CharSequence);
     method public android.view.autofill.Dataset build();
-    method public android.view.autofill.Dataset.Builder requiresCustomAuthentication(android.os.Bundle, int);
-    method public android.view.autofill.Dataset.Builder requiresFingerprintAuthentication(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.Bundle, int);
+    method public android.view.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
     method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
     method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
   }
@@ -47080,27 +47190,14 @@
   }
 
   public static final class FillResponse.Builder {
-    ctor public FillResponse.Builder();
+    ctor public FillResponse.Builder(java.lang.String);
     method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
     method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
     method public android.view.autofill.FillResponse build();
-    method public android.view.autofill.FillResponse.Builder requiresCustomAuthentication(android.os.Bundle, int);
-    method public android.view.autofill.FillResponse.Builder requiresFingerprintAuthentication(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.Bundle, int);
+    method public android.view.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender);
     method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
   }
 
-  public abstract class VirtualViewDelegate {
-    ctor public VirtualViewDelegate();
-    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
-  }
-
-  public static abstract class VirtualViewDelegate.Callback {
-    ctor public VirtualViewDelegate.Callback();
-    method public void onAutoFillInputUpdated(int, android.graphics.Rect, int);
-    method public void onNodeRemoved(int...);
-    method public void onValueChanged(int);
-  }
-
 }
 
 package android.view.inputmethod {
@@ -50603,6 +50700,7 @@
     method public int getAutoSizeMaxTextSize();
     method public int getAutoSizeMinTextSize();
     method public int getAutoSizeStepGranularity();
+    method public int[] getAutoSizeTextPresetSizes();
     method public int getAutoSizeTextType();
     method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
@@ -50716,6 +50814,7 @@
     method public void setAutoSizeMaxTextSize(int, float);
     method public void setAutoSizeMinTextSize(int, float);
     method public void setAutoSizeStepGranularity(int, float);
+    method public void setAutoSizeTextPresetSizes(int[]);
     method public void setAutoSizeTextType(int);
     method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
@@ -50854,6 +50953,7 @@
     method public void setIs24HourView(java.lang.Boolean);
     method public void setMinute(int);
     method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+    method public boolean validateInput();
     field public static final int MODE_CLOCK = 2; // 0x2
     field public static final int MODE_SPINNER = 1; // 0x1
   }
@@ -51255,6 +51355,8 @@
     field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
     field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
     field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+    field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+    field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
     field public static final int OP_INVOKE_STATIC = 113; // 0x71
     field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
     field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -54549,12 +54651,15 @@
   }
 
   public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
     method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
     method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
     method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
     method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
     method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
     method public boolean isVarargsCollector();
     method public java.lang.invoke.MethodType type();
@@ -54588,17 +54693,23 @@
     method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
     method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
     method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
     method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandles.Lookup lookup();
     method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
     method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
     method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
   }
 
@@ -54615,6 +54726,7 @@
     method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
+    method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
     method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 7901737..a6d2986 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -352,7 +352,7 @@
 
 bool BootAnimation::android()
 {
-    ALOGD("BootAnimationShownTiming: BootAnimation start time: %" PRId64 "ms", elapsedRealtime());
+    ALOGD("BootAnimationShownTiming start time: %" PRId64 "ms", elapsedRealtime());
     initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
     initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
 
@@ -878,7 +878,7 @@
     const int animationX = (mWidth - animation.width) / 2;
     const int animationY = (mHeight - animation.height) / 2;
 
-    ALOGD("BootAnimationShownTiming: BootAnimation start time: %" PRId64 "ms", elapsedRealtime());
+    ALOGD("BootAnimationShownTiming start time: %" PRId64 "ms", elapsedRealtime());
     for (size_t i=0 ; i<pcount ; i++) {
         const Animation::Part& part(animation.parts[i]);
         const size_t fcount = part.frames.size();
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 63f6c92..8e9b91d 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.IUserManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -51,6 +50,7 @@
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
     private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
+    private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
 
     private ComponentName mComponent;
     private String mAccountId;
@@ -69,6 +69,7 @@
                 "usage: telecom set-default-dialer <PACKAGE>\n" +
                 "usage: telecom get-default-dialer\n" +
                 "usage: telecom get-system-dialer\n" +
+                "usage: telecom wait-on-handlers\n" +
                 "\n" +
                 "telecom set-phone-account-enabled: Enables the given phone account, if it has \n" +
                 " already been registered with Telecom.\n" +
@@ -80,7 +81,9 @@
                 "\n" +
                 "telecom get-default-dialer: Displays the current default dialer. \n" +
                 "\n" +
-                "telecom get-system-dialer: Displays the current system dialer. \n"
+                "telecom get-system-dialer: Displays the current system dialer. \n" +
+                "\n" +
+                "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
                 );
     }
 
@@ -125,6 +128,9 @@
             case COMMAND_GET_SYSTEM_DIALER:
                 runGetSystemDialer();
                 break;
+            case COMMAND_WAIT_ON_HANDLERS:
+                runWaitOnHandler();
+                break;
             default:
                 throw new IllegalArgumentException ("unknown command '" + command + "'");
         }
@@ -192,6 +198,10 @@
         System.out.println(mTelecomService.getSystemDialerPackage());
     }
 
+    private void runWaitOnHandler() throws RemoteException {
+
+    }
+
     private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException{
         final ComponentName component = parseComponentName(nextArgRequired());
         final String accountId = nextArgRequired();
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
index 73e46f1..28a5646 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
@@ -32,8 +32,6 @@
 import android.view.MotionEvent.PointerProperties;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.internal.util.Predicate;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -261,7 +259,7 @@
     }
 
     /**
-     * Returns a Runnable for use in {@link #runAndWaitForEvents(Runnable, Predicate, long) to
+     * Returns a Runnable for use in {@link #runAndWaitForEvents(Runnable, AccessibilityEventFilter, long) to
      * perform a click.
      *
      * @param x coordinate
diff --git a/core/java/android/accessibilityservice/AccessibilityButtonController.java b/core/java/android/accessibilityservice/AccessibilityButtonController.java
new file mode 100644
index 0000000..c3a5dab
--- /dev/null
+++ b/core/java/android/accessibilityservice/AccessibilityButtonController.java
@@ -0,0 +1,223 @@
+/*
+ * 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 android.accessibilityservice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+/**
+ * Controller for the accessibility button within the system's navigation area
+ * <p>
+ * This class may be used to query the accessibility button's state and register
+ * callbacks for interactions with and state changes to the accessibility button when
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This class and
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} should not be used as
+ * the sole means for offering functionality to users via an {@link AccessibilityService}.
+ * Some device implementations may choose not to provide a software-rendered system
+ * navigation area, making this affordance permanently unavailable.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> On device implementations where the accessibility button is
+ * supported, it may not be available at all times, such as when a foreground application uses
+ * {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}. A user may also choose to assign
+ * this button to another accessibility service or feature. In each of these cases, a
+ * registered {@link AccessibilityButtonCallback}'s
+ * {@link AccessibilityButtonCallback#onAvailabilityChanged(AccessibilityButtonController, boolean)}
+ * method will be invoked to provide notifications of changes in the accessibility button's
+ * availability to the registering service.
+ * </p>
+ */
+public final class AccessibilityButtonController {
+    private static final String LOG_TAG = "A11yButtonController";
+
+    private final IAccessibilityServiceConnection mServiceConnection;
+    private final Object mLock;
+    private ArrayMap<AccessibilityButtonCallback, Handler> mCallbacks;
+
+    AccessibilityButtonController(@NonNull IAccessibilityServiceConnection serviceConnection) {
+        mServiceConnection = serviceConnection;
+        mLock = new Object();
+    }
+
+    /**
+     * Retrieves whether the accessibility button in the system's navigation area is
+     * available to the calling service.
+     * <p>
+     * <strong>Note:</strong> If the service is not yet connected (e.g.
+     * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
+     * service has been disconnected, this method will have no effect and return {@code false}.
+     * </p>
+     *
+     * @return {@code true} if the accessibility button in the system's navigation area is
+     * available to the calling service, {@code false} otherwise
+     */
+    public boolean isAccessibilityButtonAvailable() {
+        try {
+            return mServiceConnection.isAccessibilityButtonAvailable();
+        } catch (RemoteException re) {
+            Slog.w(LOG_TAG, "Failed to get accessibility button availability.", re);
+            re.rethrowFromSystemServer();
+            return false;
+        }
+    }
+
+    /**
+     * Registers the provided {@link AccessibilityButtonCallback} for interaction and state
+     * changes callbacks related to the accessibility button.
+     *
+     * @param callback the callback to add, must be non-null
+     */
+    public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback) {
+        registerAccessibilityButtonCallback(callback, null);
+    }
+
+    /**
+     * Registers the provided {@link AccessibilityButtonCallback} for interaction and state
+     * change callbacks related to the accessibility button. The callback will occur on the
+     * specified {@link Handler}'s thread, or on the services's main thread if the handler is
+     * {@code null}.
+     *
+     * @param callback the callback to add, must be non-null
+     * @param handler the handler on which to callback should execute, or {@code null} to
+     *                execute on the service's main thread
+     */
+    public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback,
+            @Nullable Handler handler) {
+        synchronized (mLock) {
+            if (mCallbacks == null) {
+                mCallbacks = new ArrayMap<>();
+            }
+
+            mCallbacks.put(callback, handler);
+        }
+    }
+
+    /**
+     * Unregisters the provided {@link AccessibilityButtonCallback} for interaction and state
+     * change callbacks related to the accessibility button.
+     *
+     * @param callback the callback to remove, must be non-null
+     */
+    public void unregisterAccessibilityButtonCallback(
+            @NonNull AccessibilityButtonCallback callback) {
+        synchronized (mLock) {
+            if (mCallbacks == null) {
+                return;
+            }
+
+            final int keyIndex = mCallbacks.indexOfKey(callback);
+            final boolean hasKey = keyIndex >= 0;
+            if (hasKey) {
+                mCallbacks.removeAt(keyIndex);
+            }
+        }
+    }
+
+    /**
+     * Dispatches the accessibility button click to any registered callbacks. This should
+     * be called on the service's main thread.
+     */
+    void dispatchAccessibilityButtonClicked() {
+        final ArrayMap<AccessibilityButtonCallback, Handler> entries;
+        synchronized (mLock) {
+            if (mCallbacks == null || mCallbacks.isEmpty()) {
+                Slog.w(LOG_TAG, "Received accessibility button click with no callbacks!");
+                return;
+            }
+
+            // Callbacks may remove themselves. Perform a shallow copy to avoid concurrent
+            // modification.
+            entries = new ArrayMap<>(mCallbacks);
+        }
+
+        for (int i = 0, count = entries.size(); i < count; i++) {
+            final AccessibilityButtonCallback callback = entries.keyAt(i);
+            final Handler handler = entries.valueAt(i);
+            if (handler != null) {
+                handler.post(() -> callback.onClicked(this));
+            } else {
+                // We're already on the main thread, just run the callback.
+                callback.onClicked(this);
+            }
+        }
+    }
+
+    /**
+     * Dispatches the accessibility button availability changes to any registered callbacks.
+     * This should be called on the service's main thread.
+     */
+    void dispatchAccessibilityButtonAvailabilityChanged(boolean available) {
+        final ArrayMap<AccessibilityButtonCallback, Handler> entries;
+        synchronized (mLock) {
+            if (mCallbacks == null || mCallbacks.isEmpty()) {
+                Slog.w(LOG_TAG,
+                        "Received accessibility button availability change with no callbacks!");
+                return;
+            }
+
+            // Callbacks may remove themselves. Perform a shallow copy to avoid concurrent
+            // modification.
+            entries = new ArrayMap<>(mCallbacks);
+        }
+
+        for (int i = 0, count = entries.size(); i < count; i++) {
+            final AccessibilityButtonCallback callback = entries.keyAt(i);
+            final Handler handler = entries.valueAt(i);
+            if (handler != null) {
+                handler.post(() -> callback.onAvailabilityChanged(this, available));
+            } else {
+                // We're already on the main thread, just run the callback.
+                callback.onAvailabilityChanged(this, available);
+            }
+        }
+    }
+
+    /**
+     * Callback for interaction with and changes to state of the accessibility button
+     * within the system's navigation area.
+     */
+    public static abstract class AccessibilityButtonCallback {
+
+        /**
+         * Called when the accessibility button in the system's navigation area is clicked.
+         *
+         * @param controller the controller used to register for this callback
+         */
+        public void onClicked(AccessibilityButtonController controller) {}
+
+        /**
+         * Called when the availability of the accessibility button in the system's
+         * navigation area has changed. The accessibility button may become unavailable
+         * because the device shopped showing the button, the button was assigned to another
+         * service, or for other reasons.
+         *
+         * @param controller the controller used to register for this callback
+         * @param available {@code true} if the accessibility button is available to this
+         *                  service, {@code false} otherwise
+         */
+        public void onAvailabilityChanged(AccessibilityButtonController controller,
+                boolean available) {
+        }
+    }
+}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index a036b6a..9e486d5 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -378,6 +378,8 @@
         void onPerformGestureResult(int sequence, boolean completedSuccessfully);
         void onFingerprintCapturingGesturesChanged(boolean active);
         void onFingerprintGesture(int gesture);
+        void onAccessibilityButtonClicked();
+        void onAccessibilityButtonAvailabilityChanged(boolean available);
     }
 
     /**
@@ -400,6 +402,7 @@
 
     private MagnificationController mMagnificationController;
     private SoftKeyboardController mSoftKeyboardController;
+    private AccessibilityButtonController mAccessibilityButtonController;
 
     private int mGestureStatusCallbackSequence;
 
@@ -431,6 +434,9 @@
         if (mMagnificationController != null) {
             mMagnificationController.onServiceConnected();
         }
+        if (mSoftKeyboardController != null) {
+            mSoftKeyboardController.onServiceConnected();
+        }
 
         // The client gets to handle service connection last, after we've set
         // up any state upon which their code may rely.
@@ -809,12 +815,10 @@
         }
 
         /**
-         * Removes all instances of the specified change listener from the list
-         * of magnification change listeners.
+         * Removes the specified change listener from the list of magnification change listeners.
          *
          * @param listener the listener to remove, must be non-null
-         * @return {@code true} if at least one instance of the listener was
-         *         removed
+         * @return {@code true} if the listener was removed, {@code false} otherwise
          */
         public boolean removeListener(@NonNull OnMagnificationChangedListener listener) {
             if (mListeners == null) {
@@ -1203,11 +1207,11 @@
         }
 
         /**
-         * Removes all instances of the specified change listener from the list of magnification
-         * change listeners.
+         * Removes the specified change listener from the list of keyboard show mode change
+         * listeners.
          *
          * @param listener the listener to remove, must be non-null
-         * @return {@code true} if at least one instance of the listener was removed
+         * @return {@code true} if the listener was removed, {@code false} otherwise
          */
         public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
             if (mListeners == null) {
@@ -1252,7 +1256,7 @@
             final ArrayMap<OnShowModeChangedListener, Handler> entries;
             synchronized (mLock) {
                 if (mListeners == null || mListeners.isEmpty()) {
-                    Slog.d(LOG_TAG, "Received soft keyboard show mode changed callback"
+                    Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback"
                             + " with no listeners registered!");
                     setSoftKeyboardCallbackEnabled(false);
                     return;
@@ -1308,9 +1312,9 @@
          * The lastto this method will be honored, regardless of any previous calls (including those
          * made by other AccessibilityServices).
          * <p>
-         * <strong>Note:</strong> If the service is not yet conected (e.g.
+         * <strong>Note:</strong> If the service is not yet connected (e.g.
          * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
-         * service has been disconnected, this method will hav no effect and return {@code false}.
+         * service has been disconnected, this method will have no effect and return {@code false}.
          *
          * @param showMode the new show mode for the soft keyboard
          * @return {@code true} on success
@@ -1349,6 +1353,39 @@
     }
 
     /**
+     * Returns the controller for the accessibility button within the system's navigation area.
+     * This instance may be used to query the accessibility button's state and register listeners
+     * for interactions with and state changes for the accessibility button when
+     * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
+     * <p>
+     * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button
+     * within a navigation area, and as such, use of this class should be considered only as an
+     * optional feature or shortcut on supported device implementations.
+     * </p>
+     *
+     * @return the accessibility button controller for this {@link AccessibilityService}
+     */
+    @NonNull
+    public final AccessibilityButtonController getAccessibilityButtonController() {
+        synchronized (mLock) {
+            if (mAccessibilityButtonController == null) {
+                mAccessibilityButtonController = new AccessibilityButtonController(
+                        AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
+            }
+            return mAccessibilityButtonController;
+        }
+    }
+
+    private void onAccessibilityButtonClicked() {
+        getAccessibilityButtonController().dispatchAccessibilityButtonClicked();
+    }
+
+    private void onAccessibilityButtonAvailabilityChanged(boolean available) {
+        getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged(
+                available);
+    }
+
+    /**
      * Performs a global action. Such an action can be performed
      * at any moment regardless of the current application or user
      * location in that application. For example going back, going
@@ -1543,6 +1580,16 @@
             public void onFingerprintGesture(int gesture) {
                 AccessibilityService.this.onFingerprintGesture(gesture);
             }
+
+            @Override
+            public void onAccessibilityButtonClicked() {
+                AccessibilityService.this.onAccessibilityButtonClicked();
+            }
+
+            @Override
+            public void onAccessibilityButtonAvailabilityChanged(boolean available) {
+                AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available);
+            }
         });
     }
 
@@ -1565,6 +1612,8 @@
         private static final int DO_GESTURE_COMPLETE = 9;
         private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10;
         private static final int DO_ON_FINGERPRINT_GESTURE = 11;
+        private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
+        private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
 
         private final HandlerCaller mCaller;
 
@@ -1645,6 +1694,17 @@
             mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture));
         }
 
+        public void onAccessibilityButtonClicked() {
+            final Message message = mCaller.obtainMessage(DO_ACCESSIBILITY_BUTTON_CLICKED);
+            mCaller.sendMessage(message);
+        }
+
+        public void onAccessibilityButtonAvailabilityChanged(boolean available) {
+            final Message message = mCaller.obtainMessageI(
+                    DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, (available ? 1 : 0));
+            mCaller.sendMessage(message);
+        }
+
         @Override
         public void executeMessage(Message message) {
             switch (message.what) {
@@ -1750,6 +1810,15 @@
                     mCallback.onFingerprintGesture(message.arg1);
                 } return;
 
+                case (DO_ACCESSIBILITY_BUTTON_CLICKED): {
+                    mCallback.onAccessibilityButtonClicked();
+                } return;
+
+                case (DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED): {
+                    final boolean available = (message.arg1 != 0);
+                    mCallback.onAccessibilityButtonAvailabilityChanged(available);
+                } return;
+
                 default :
                     Log.w(LOG_TAG, "Unknown message type " + message.what);
             }
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 18e57cb..e135ffd 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -306,6 +306,12 @@
      */
     public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 0x00000080;
 
+     /**
+     * This flag indicates to the system that the accessibility service requests that an
+     * accessibility button be shown within the system's navigation area, if available.
+     */
+    public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100;
+
     /**
      * This flag requests that all fingerprint gestures be sent to the accessibility service.
      * It is handled in {@link FingerprintGestureController}
@@ -396,6 +402,8 @@
      * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
      * @see #FLAG_REPORT_VIEW_IDS
      * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
+     * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
+     * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
      */
     public int flags;
 
@@ -631,7 +639,7 @@
      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
-     * @see #CAPABILITY_FILTER_KEY_EVENTS
+     * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
      * @see #CAPABILITY_CAN_PERFORM_GESTURES
      */
@@ -648,7 +656,7 @@
      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
-     * @see #CAPABILITY_FILTER_KEY_EVENTS
+     * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
      * @see #CAPABILITY_CAN_PERFORM_GESTURES
      *
@@ -936,6 +944,8 @@
                 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
             case FLAG_ENABLE_ACCESSIBILITY_VOLUME:
                 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME";
+            case FLAG_REQUEST_ACCESSIBILITY_BUTTON:
+                return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
             case FLAG_CAPTURE_FINGERPRINT_GESTURES:
                 return "FLAG_CAPTURE_FINGERPRINT_GESTURES";
             default:
@@ -960,7 +970,7 @@
             case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
                 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
             case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
-                return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
+                return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS";
             case CAPABILITY_CAN_CONTROL_MAGNIFICATION:
                 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
             case CAPABILITY_CAN_PERFORM_GESTURES:
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 3f778ad..4e96b8f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -50,4 +50,8 @@
     void onFingerprintCapturingGesturesChanged(boolean capturing);
 
     void onFingerprintGesture(int gesture);
+
+    void onAccessibilityButtonClicked();
+
+    void onAccessibilityButtonAvailabilityChanged(boolean available);
 }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 5499bd5..7a1931718 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -37,7 +37,8 @@
 
     boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
         long accessibilityNodeId, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, int flags, long threadId);
+        IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
+        in Bundle arguments);
 
     boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
         String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
@@ -88,6 +89,8 @@
 
     void setSoftKeyboardCallbackEnabled(boolean enabled);
 
+    boolean isAccessibilityButtonAvailable();
+
     void sendGesture(int sequence, in ParceledListSlice gestureSteps);
 
     boolean isFingerprintGestureDetectionAvailable();
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index def0ff9..0263681 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -338,21 +338,24 @@
         "android.accounts.LOGIN_ACCOUNTS_CHANGED";
 
     /**
-     * Uid key to set default visibility for applications targeting API level
+     * Key to set default visibility for applications targeting API level
      * {@link android.os.Build.VERSION_CODES#O} or above and don't have the same signature as
      * authenticator See {@link #getAccountVisibility}. If the value was not set by authenticator
-     * USER_MANAGED_NOT_VISIBLE is used.
+     * {@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE} is used.
      */
-    public static final int UID_KEY_DEFAULT_VISIBILITY = -2;
+    public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE =
+            "android.accounts.key_legacy_visible";
 
     /**
-     * Uid key to set visibility for applications targeting API level below
-     * {@link android.os.Build.VERSION_CODES#O} with GET_ACCOUNS permission, or applications with
-     * any targeting API level with the same signature as authenticator. See
-     * {@link #getAccountVisibility}. If the value was not set by authenticator USER_MANAGED_VISIBLE
-     * is used.
+     * Key to set visibility for applications targeting API level below
+     * {@link android.os.Build.VERSION_CODES#O} with
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission, or applications with any
+     * targeting API level with the same signature as authenticator. See
+     * {@link #getAccountVisibility}. If the value was not set by authenticator
+     * {@link #VISIBILITY_USER_MANAGED_VISIBLE} is used.
      */
-    public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3;
+    public static final String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE =
+            "android.accounts.key_legacy_not_visible";
 
     /**
      * @hide
@@ -565,12 +568,14 @@
     }
 
     /**
-     * Returns the accounts visible to the specified package, in an environment where some apps
-     * are not authorized to view all accounts. This method can only be called by system apps.
+     * Returns the accounts visible to the specified package, in an environment where some apps are
+     * not authorized to view all accounts. This method can only be called by system apps and
+     * authenticators managing the type
+     *
      * @param type The type of accounts to return, null to retrieve all accounts
      * @param packageName The package name of the app for which the accounts are to be returned
-     * @return An array of {@link Account}, one per matching account.  Empty
-     *     (never null) if no accounts of the specified type have been added.
+     * @return An array of {@link Account}, one per matching account. Empty (never null) if no
+     *         accounts of the specified type have been added.
      */
     @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
@@ -609,7 +614,8 @@
      *
      * <p>
      * <b>NOTE:</b> If targeting your app to work on API level
-     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, GET_ACCOUNTS permission is
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before,
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission is
      * needed for those platforms, irrespective of uid or signature match. See docs for this
      * function in API level {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
      *
@@ -750,7 +756,8 @@
      * accounts managed by AbstractAccountAuthenticators whose signature matches the client.
      * <p>
      * <b>NOTE:</b> If targeting your app to work on API level
-     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, GET_ACCOUNTS permission is
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before,
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission is
      * needed for those platforms, irrespective of uid or signature match. See docs for this
      * function in API level {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
      *
@@ -822,9 +829,8 @@
     }
 
     /**
-     * Adds an account directly to the AccountManager. Additionally this makes the Account visible
-     * to desired UIDs of applications on the device, and sends directed broadcasts to these
-     * individual applications.
+     * Adds an account directly to the AccountManager. Additionally it specifies Account visiblity
+     * for given list of packages.
      * <p>
      * Normally used by sign-up wizards associated with authenticators, not directly by
      * applications.
@@ -841,14 +847,14 @@
      * @param account The {@link Account} to add
      * @param password The password to associate with the account, null for none
      * @param extras String values to use for the account's userdata, null for none
-     * @param visibility Map from uid to visibility values which will be set before account is
-     *        added. See getAccountVisibility for possilbe values.
+     * @param visibility Map from packageName to visibility values which will be set before account
+     *        is added. See {@link #getAccountVisibility} for possible values.
      *
      * @return True if the account was successfully added, false if the account already exists, the
      *         account is null, or another error occurs.
      */
     public boolean addAccountExplicitly(Account account, String password, Bundle extras,
-            Map<Integer, Integer> visibility) {
+            Map<String, Integer> visibility) {
         if (account == null)
             throw new IllegalArgumentException("account is null");
         try {
@@ -860,20 +866,22 @@
     }
 
     /**
-     * Returns UIDs of applications for which visibility of given account was explicitly set.
+     * Returns package names and visibility which were explicitly set for given account.
      * <p>
      * This method requires the caller to have a signature match with the authenticator that owns
      * the specified account.
      *
      * @param account The account for which visibility data should be returned.
      *
-     * @return Map from uid to visibility for given account.
+     * @return Map from package names to visibility for given account.
      */
-    public Map<Integer, Integer> getUidsAndVisibilityForAccount(Account account) {
+    public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
         try {
+            if (account == null)
+                throw new IllegalArgumentException("account is null");
             @SuppressWarnings("unchecked")
-            Map<Integer, Integer> result = (Map<Integer, Integer>) mService
-                    .getUidsAndVisibilityForAccount(account);
+            Map<String, Integer> result = (Map<String, Integer>) mService
+                    .getPackagesAndVisibilityForAccount(account);
             return result;
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
@@ -907,30 +915,34 @@
     }
 
     /**
-     * Set visibility value of given account to certain UID.
+     * Set visibility value of given account to certain packageName.
+     * Package name must match installed application, or be equal to
+     * {@link #PACKAGE_NAME_KEY_LEGACY_VISIBLE} or {@link #PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE}.
      * <p>
      * See {@link #getAccountVisibility} for possible values.
      * <p>
      * This method requires the caller to have a signature match with the authenticator that owns
      * the specified account.
      *
-     * @param account Account to make visible.
-     * @param uid The UID of the application to modify account visibility.
+     * @param account Account to update visibility
+     * @param packageName Package name of the application to modify account visibility.
      * @param visibility - new visibility value.
      *
      * @return True if visibility value was succesfully updated.
      */
-    public boolean setAccountVisibility(Account account, int uid,
+    public boolean setAccountVisibility(Account account, String packageName,
             @AccountVisibility int visibility) {
+        if (account == null)
+            throw new IllegalArgumentException("account is null");
         try {
-            return mService.setAccountVisibility(account, uid, visibility);
+            return mService.setAccountVisibility(account, packageName, visibility);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Gets visibility of certain account for given UID. Possible returned values are:
+     * Get visibility of certain account for given application. Possible returned values are:
      * <ul>
      * <li>{@link #VISIBILITY_UNDEFINED}</li>
      * <li>{@link #VISIBILITY_VISIBLE}</li>
@@ -944,13 +956,15 @@
      * the specified account.
      *
      * @param account Account to get visibility.
-     * @param uid The UID of the application to get account visibility.
+     * @param packageName Package name of the application to get account visibility
      *
-     * @return int Visibility for given account and uid.
+     * @return int Visibility for given account and package.
      */
-    public @AccountVisibility int getAccountVisibility(Account account, int uid) {
+    public @AccountVisibility int getAccountVisibility(Account account, String packageName) {
+        if (account == null)
+            throw new IllegalArgumentException("account is null");
         try {
-            return mService.getAccountVisibility(account, uid);
+            return mService.getAccountVisibility(account, packageName);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 95fdfef..35011b5 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -437,7 +437,7 @@
         }
         if (oldVisibility != null
                 && oldVisibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) {
-            AccountManager.get(this).setAccountVisibility(account, mCallingUid,
+            AccountManager.get(this).setAccountVisibility(account, mCallingPackage,
                     AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
         }
         Bundle bundle = new Bundle();
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 63a0919..e0fdac1 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -108,15 +108,12 @@
     void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
         String statusToken);
 
-    /* Returns Map<Integer, Integer> from UID to visibility with all values stored for given account*/
-    Map getUidsAndVisibilityForAccount(in Account account);
-
+    /* Returns Map<String, Integer> from package name to visibility with all values stored for given account */
+    Map getPackagesAndVisibilityForAccount(in Account account);
     boolean addAccountExplicitlyWithVisibility(in Account account, String password, in Bundle extras,
             in Map visibility);
-
-    boolean setAccountVisibility(in Account a, int uid, int newVisibility);
-    int getAccountVisibility(in Account a, int uid);
-
+    boolean setAccountVisibility(in Account a, in String packageName, int newVisibility);
+    int getAccountVisibility(in Account a, in String packageName);
     /* Type may be null returns Map <Account, Integer>*/
     Map getAccountsAndVisibilityForPackage(in String packageName, in String accountType);
 
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 55ac1f4..558fdc6 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -637,13 +637,16 @@
     public void setCurrentFraction(float fraction) {
         initAnimation();
         fraction = clampFraction(fraction);
-        long seekTime = (long) (getScaledDuration() * fraction);
-        long currentTime = AnimationUtils.currentAnimationTimeMillis();
-        mStartTime = currentTime - seekTime;
         mStartTimeCommitted = true; // do not allow start time to be compensated for jank
-        if (!isPulsingInternal()) {
-            // If the animation loop hasn't started, the startTime will be adjusted in the first
-            // frame based on seek fraction.
+        if (isPulsingInternal()) {
+            long seekTime = (long) (getScaledDuration() * fraction);
+            long currentTime = AnimationUtils.currentAnimationTimeMillis();
+            // Only modify the start time when the animation is running. Seek fraction will ensure
+            // non-running animations skip to the correct start time.
+            mStartTime = currentTime - seekTime;
+        } else {
+            // If the animation loop hasn't started, or during start delay, the startTime will be
+            // adjusted once the delay has passed based on seek fraction.
             mSeekFraction = fraction;
         }
         mOverallFraction = fraction;
@@ -1028,7 +1031,7 @@
         // started-but-not-yet-reached-the-first-frame phase.
         mLastFrameTime = -1;
         mFirstFrameTime = -1;
-        addAnimationCallback((long) (mStartDelay * sDurationScale));
+        addAnimationCallback(0);
 
         if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
             // If there's no start delay, init the animation and notify start listeners right away
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6f95309..edf60b4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -49,7 +49,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -74,8 +73,6 @@
 import android.os.StrictMode;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.service.autofill.AutoFillService;
-import android.service.autofill.IAutoFillAppCallback;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
@@ -116,7 +113,6 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.autofill.AutoFillId;
 import android.view.autofill.AutoFillManager;
 import android.view.autofill.AutoFillSession;
 import android.widget.AdapterView;
@@ -127,7 +123,6 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -1700,16 +1695,21 @@
     }
 
     /**
-     * Lazily gets the {@link IAutoFillAppCallback} for this activitity.
-     *
-     * <p>This callback is used by the {@link AutoFillService} app to auto-fill the activity fields.
+     * Lazily attachs the activity to the current {@link AutoFillSession} (if any).
      */
-    IAutoFillAppCallback getAutoFillCallback() {
+    void attachToAutoFillSession() {
         synchronized (this) {
             if (mAutoFillSession == null) {
-                mAutoFillSession = new AutoFillSession(this);
+                final AutoFillManager afm = getSystemService(AutoFillManager.class);
+                if (afm != null) {
+                    mAutoFillSession = afm.getSession();
+                    if (mAutoFillSession != null) {
+                        mAutoFillSession.attachActivity(this);
+                    } else {
+                        Log.w(TAG, "attachToAutoFillSession(): not in a session");
+                    }
+                }
             }
-            return mAutoFillSession.getCallback();
         }
     }
 
@@ -1744,13 +1744,14 @@
             final MenuItem item = menu.getItem(i);
             final CharSequence title = item.getTitle();
             final char alphaShortcut = item.getAlphabeticShortcut();
+            final int alphaModifiers = item.getAlphabeticModifiers();
             if (title != null && alphaShortcut != MIN_VALUE) {
                 if (group == null) {
                     final int resource = mApplication.getApplicationInfo().labelRes;
                     group = new KeyboardShortcutGroup(resource != 0 ? getString(resource) : null);
                 }
                 group.addItem(new KeyboardShortcutInfo(
-                    title, alphaShortcut, KeyEvent.META_CTRL_ON));
+                    title, alphaShortcut, alphaModifiers));
             }
         }
         if (group != null) {
@@ -1798,6 +1799,10 @@
         getApplication().dispatchActivityStopped(this);
         mTranslucentCallback = null;
         mCalled = true;
+        if (mAutoFillSession != null && isFinishing()) {
+            mAutoFillSession.finishSession();
+            mAutoFillSession = null;
+        }
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index e848080..89510d9 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -154,12 +154,6 @@
     public abstract List<IBinder> getTopVisibleActivities();
 
     /**
-     * Returns the top, focused activity of the currently visible stack, but only if it belongs to
-     * the given UID.
-     */
-    public abstract IBinder getTopVisibleActivity(int uid);
-
-    /**
      * Callback for window manager to let activity manager know that docked stack changes its
      * minimized state.
      */
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 04510da..0b9479d 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -33,6 +33,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
 import android.util.Pair;
 import android.util.Slog;
@@ -1342,7 +1343,7 @@
                 + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
     }
 
-    private static class HideWindowListener extends Transition.TransitionListenerAdapter
+    private static class HideWindowListener extends TransitionListenerAdapter
         implements ExitTransitionCoordinator.HideSharedElementsCallback {
         private final Window mWindow;
         private final ExitTransitionCoordinator mExit;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d5371f8..dffd81f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2931,7 +2931,7 @@
             if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutoFill) {
                 structure = new AssistStructure(r.activity, forAutoFill);
                 Intent activityIntent = r.activity.getIntent();
-                boolean addAutoFillCallback = false;
+                boolean attachToSession = false;
                 // TODO(b/33197203): re-evaluate conditions below for auto-fill. In particular,
                 // FLAG_SECURE might be allowed on AUTO_FILL but not on AUTO_FILL_SAVE)
                 boolean notSecure = r.window == null ||
@@ -2939,7 +2939,7 @@
                                 & WindowManager.LayoutParams.FLAG_SECURE) == 0;
                 if (activityIntent != null && notSecure) {
                     if (forAutoFill) {
-                        addAutoFillCallback = true;
+                        attachToSession = true;
                     } else {
                         Intent intent = new Intent(activityIntent);
                         intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
@@ -2953,18 +2953,13 @@
                     } else {
                         // activityIntent is unlikely to be null, but if it is, we should still
                         // set the auto-fill callback.
-                        addAutoFillCallback = notSecure;
+                        attachToSession = notSecure;
                     }
                 }
                 if (!forAutoFill) {
                     r.activity.onProvideAssistContent(content);
-                } else if (addAutoFillCallback) {
-                    IAutoFillAppCallback cb = r.activity.getAutoFillCallback();
-                    if (cb != null) {
-                        data.putBinder(AutoFillService.KEY_CALLBACK, cb.asBinder());
-                    } else {
-                        Slog.w(TAG, "handleRequestAssistContextExtras(): callback was GCed");
-                    }
+                } else if (attachToSession) {
+                    r.activity.attachToAutoFillSession();
                 }
             }
         }
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 1eaf029..a512350 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -24,6 +24,7 @@
 import android.os.Parcelable;
 import android.os.ResultReceiver;
 import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionSet;
 import android.transition.Visibility;
 import android.util.ArrayMap;
@@ -916,7 +917,7 @@
 
     protected void onTransitionsComplete() {}
 
-    protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
+    protected class ContinueTransitionListener extends TransitionListenerAdapter {
         @Override
         public void onTransitionStart(Transition transition) {
             mIsStartingTransition = false;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 603126b..fb927e9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -247,8 +247,10 @@
     public static final int OP_REQUEST_INSTALL_PACKAGES = 66;
     /** @hide Enter picture-in-picture when hidden. */
     public static final int OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67;
+    /** @hide Instant app start foreground service. */
+    public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
     /** @hide */
-    public static final int _NUM_OP = 68;
+    public static final int _NUM_OP = 69;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -351,6 +353,9 @@
             = "android:get_accounts";
     public static final String OPSTR_READ_PHONE_NUMBER
             = "android:read_phone_number";
+    /** @hide */
+    public static final String OPSTR_INSTANT_APP_START_FOREGROUND
+            = "android:instant_app_start_foreground";
 
     private static final int[] RUNTIME_PERMISSIONS_OPS = {
             // Contacts
@@ -467,6 +472,7 @@
             OP_READ_PHONE_NUMBER,
             OP_REQUEST_INSTALL_PACKAGES,
             OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE,
+            OP_INSTANT_APP_START_FOREGROUND,
     };
 
     /**
@@ -542,6 +548,7 @@
             OPSTR_READ_PHONE_NUMBER,
             null, // OP_REQUEST_INSTALL_PACKAGES
             null,
+            OPSTR_INSTANT_APP_START_FOREGROUND,
     };
 
     /**
@@ -617,6 +624,7 @@
             "READ_PHONE_NUMBER",
             "REQUEST_INSTALL_PACKAGES",
             "OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE",
+            "INSTANT_APP_START_FOREGROUND",
     };
 
     /**
@@ -692,6 +700,7 @@
             Manifest.permission.READ_PHONE_NUMBER,
             Manifest.permission.REQUEST_INSTALL_PACKAGES,
             null, // no permission for entering picture-in-picture on hide
+            Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
     };
 
     /**
@@ -768,6 +777,7 @@
             null, // READ_PHONE_NUMBER
             null, // REQUEST_INSTALL_PACKAGES
             null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
+            null, // INSTANT_APP_START_FOREGROUND
     };
 
     /**
@@ -843,6 +853,7 @@
             false, // READ_PHONE_NUMBER
             false, // REQUEST_INSTALL_PACKAGES
             false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
+            false, // INSTANT_APP_START_FOREGROUND
     };
 
     /**
@@ -917,6 +928,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES
             AppOpsManager.MODE_ALLOWED,  // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
+            AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND
     };
 
     /**
@@ -995,6 +1007,7 @@
             false,
             false, // OP_REQUEST_INSTALL_PACKAGES
             false, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
+            false,
     };
 
     /**
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 66b2355..c88448a 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -813,8 +813,11 @@
     /**
      * Reverses the execution of the operations within this transaction. The Fragment states will
      * only be modified if optimizations are not allowed.
+     *
+     * @param moveToState {@code true} if added fragments should be moved to their final state
+     *                    in unoptimized transactions
      */
-    void executePopOps() {
+    void executePopOps(boolean moveToState) {
         for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
             final Op op = mOps.get(opNum);
             Fragment f = op.fragment;
@@ -860,7 +863,7 @@
                 mManager.moveFragmentToExpectedState(f);
             }
         }
-        if (!mAllowOptimization) {
+        if (!mAllowOptimization && moveToState) {
             mManager.moveToState(mManager.mCurState, true);
         }
     }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9db2b92..16989c0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1896,7 +1896,7 @@
                 pi.getResDir(),
                 pi.getSplitResDirs(),
                 pi.getOverlayDirs(),
-                pi.getSharedLibraries(),
+                pi.getApplicationInfo().sharedLibraryFiles,
                 displayId,
                 overrideConfig,
                 compatInfo,
@@ -2180,7 +2180,7 @@
                 packageInfo.getResDir(),
                 splitDirs,
                 packageInfo.getOverlayDirs(),
-                packageInfo.getSharedLibraries(),
+                packageInfo.getApplicationInfo().sharedLibraryFiles,
                 displayId,
                 overrideConfiguration,
                 compatInfo,
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 0454acb..445b687 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -26,6 +26,7 @@
 import android.os.ResultReceiver;
 import android.text.TextUtils;
 import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.view.View;
@@ -491,7 +492,7 @@
                 sharedElementTransitionStarted();
                 sharedElementTransitionComplete();
             } else {
-                sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+                sharedElementTransition.addListener(new TransitionListenerAdapter() {
                     @Override
                     public void onTransitionStart(Transition transition) {
                         sharedElementTransitionStarted();
@@ -592,7 +593,7 @@
                 });
                 mBackgroundAnimator.start();
             } else if (transition != null) {
-                transition.addListener(new Transition.TransitionListenerAdapter() {
+                transition.addListener(new TransitionListenerAdapter() {
                     @Override
                     public void onTransitionEnd(Transition transition) {
                         transition.removeListener(this);
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index f04eef2..29e10d8 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -31,6 +31,7 @@
 import android.os.Message;
 import android.os.ResultReceiver;
 import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
 import android.view.View;
 import android.view.ViewGroup;
@@ -161,7 +162,7 @@
 
     private void startSharedElementExit(final ViewGroup decorView) {
         Transition transition = getSharedElementExitTransition();
-        transition.addListener(new Transition.TransitionListenerAdapter() {
+        transition.addListener(new TransitionListenerAdapter() {
             @Override
             public void onTransitionEnd(Transition transition) {
                 transition.removeListener(this);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 4f68ec7..d32cf3c 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2077,8 +2077,6 @@
             } else {
                 record.trackAddedFragmentsInPop(mTmpAddedFragments);
             }
-            final int bumpAmount = isPop ? -1 : 1;
-            record.bumpBackStackNesting(bumpAmount);
             addToBackStack = addToBackStack || record.mAddToBackStack;
         }
         mTmpAddedFragments.clear();
@@ -2172,7 +2170,7 @@
                 if (isPop) {
                     record.executeOps();
                 } else {
-                    record.executePopOps();
+                    record.executePopOps(false);
                 }
 
                 // move to the end
@@ -2281,8 +2279,13 @@
             final BackStackRecord record = records.get(i);
             final boolean isPop = isRecordPop.get(i);
             if (isPop) {
-                record.executePopOps();
+                record.bumpBackStackNesting(-1);
+                // Only execute the add operations at the end of
+                // all transactions.
+                boolean moveToState = i == (endIndex - 1);
+                record.executePopOps(moveToState);
             } else {
+                record.bumpBackStackNesting(1);
                 record.executeOps();
             }
         }
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index 2570d92..f62ab8d 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -18,6 +18,7 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
 import android.transition.TransitionSet;
 import android.util.ArrayMap;
@@ -332,7 +333,7 @@
             OneShotPreDrawListener.add(exitingFragment.mContainer, () -> {
                 setViewVisibility(exitingViews, View.INVISIBLE);
             });
-            exitTransition.addListener(new Transition.TransitionListenerAdapter() {
+            exitTransition.addListener(new TransitionListenerAdapter() {
                 @Override
                 public void onTransitionEnd(Transition transition) {
                     transition.removeListener(this);
@@ -995,7 +996,7 @@
             final Transition enterTransition, final ArrayList<View> enteringViews,
             final Transition exitTransition, final ArrayList<View> exitingViews,
             final TransitionSet sharedElementTransition, final ArrayList<View> sharedElementsIn) {
-        overalTransition.addListener(new Transition.TransitionListenerAdapter() {
+        overalTransition.addListener(new TransitionListenerAdapter() {
             @Override
             public void onTransitionStart(Transition transition) {
                 if (enterTransition != null) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 3cc6282..c842f78 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -145,6 +145,7 @@
             int flags, in Bundle arguments, in IInstrumentationWatcher watcher,
             in IUiAutomationConnection connection, int userId,
             in String abiOverride);
+    void addInstrumentationResults(in IApplicationThread target, in Bundle results);
     void finishInstrumentation(in IApplicationThread target, int resultCode,
             in Bundle results);
     /**
@@ -584,7 +585,7 @@
     void unregisterTaskStackListener(ITaskStackListener listener);
     void moveStackToDisplay(int stackId, int displayId);
     boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
-            int resultCode, in IBinder activityToken);
+                                in IBinder activityToken);
     void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
     int restartUserInBackground(int userId);
 
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 58cd310..cc6f6e1 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -40,7 +40,7 @@
 {
     void cancelAllNotifications(String pkg, int userId);
 
-    void clearData(String pkg, int uid);
+    void clearData(String pkg, int uid, boolean fromApp);
     void enqueueToast(String pkg, ITransientNotification callback, int duration);
     void cancelToast(String pkg, ITransientNotification callback);
     void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b1bdea1..4db29fb 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -186,11 +186,25 @@
             }
         }
     }
-    
+
+    /**
+     * Report some results in the middle of instrumentation execution.  Later results (including
+     * those provided by {@link #finish}) will be combined with {@link Bundle#putAll}.
+     */
+    public void addResults(Bundle results) {
+        IActivityManager am = ActivityManager.getService();
+        try {
+            am.addInstrumentationResults(mThread.getApplicationThread(), results);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Terminate instrumentation of the application.  This will cause the
      * application process to exit, removing this instrumentation from the next
-     * time the application is started. 
+     * time the application is started.  If multiple processes are currently running
+     * for this instrumentation, all of those processes will be killed.
      *  
      * @param resultCode Overall success/failure of instrumentation. 
      * @param results Any results to send back to the code that started the 
@@ -278,6 +292,18 @@
     }
 
     /**
+     * Return the name of the process this instrumentation is running in.  Note this should
+     * only be used for testing and debugging.  If you are thinking about using this to,
+     * for example, conditionalize what is initialized in an Application class, it is strongly
+     * recommended to instead use lazy initialization (such as a getter for the state that
+     * only creates it when requested).  This can greatly reduce the work your process does
+     * when created for secondary things, such as to receive a broadcast.
+     */
+    public String getProcessName() {
+        return mThread.getProcessName();
+    }
+
+    /**
      * Check whether this instrumentation was started with profiling enabled.
      * 
      * @return Returns true if profiling was enabled when starting, else false.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 17f5edd..7ed96af 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -311,7 +311,7 @@
                 }
 
                 mResources = ResourcesManager.getInstance().getResources(null, mResDir,
-                        splitPaths, mOverlayDirs, mSharedLibraries,
+                        splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
                         Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
                         getClassLoader());
             }
@@ -923,10 +923,6 @@
         return mOverlayDirs;
     }
 
-    public String[] getSharedLibraries() {
-        return mSharedLibraries;
-    }
-
     public String getDataDir() {
         return mDataDir;
     }
@@ -958,7 +954,7 @@
             }
 
             mResources = ResourcesManager.getInstance().getResources(null, mResDir,
-                    splitPaths, mOverlayDirs, mSharedLibraries,
+                    splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
                     Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
                     getClassLoader());
         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2c1cdd6..9ef40b4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -28,6 +28,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ShortcutInfo;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -48,7 +49,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
 import android.text.BidiFormatter;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
@@ -223,13 +223,11 @@
      * superimposed over the icon in the status bar. Starting with
      * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by
      * {@link Notification.Builder} has displayed the number in the expanded notification view.
+     * Starting with {@link android.os.Build.VERSION_CODES#O}, the number may be displayed as a
+     * badge icon in Launchers that support badging.
      *
-     * If the number is 0 or negative, it is never shown.
-     *
-     * @deprecated this number is not shown anymore
      */
-    @Deprecated
-    public int number;
+    public int number = 1;
 
     /**
      * The intent to execute when the expanded status entry is clicked.  If
@@ -634,9 +632,10 @@
 
     /**
      * Special value of {@link #color} used as a place holder for an invalid color.
+     * @hide
      */
     @ColorInt
-    private static final int COLOR_INVALID = 1;
+    public static final int COLOR_INVALID = 1;
 
     /**
      * Sphere of visibility of this notification, which affects how and when the SystemUI reveals
@@ -1074,6 +1073,26 @@
     private String mChannelId;
     private long mTimeout;
 
+    private String mShortcutId;
+
+    /**
+     * If this notification is being shown as a badge, always show as a number.
+     */
+    public static final int BADGE_ICON_NONE = 0;
+
+    /**
+     * If this notification is being shown as a badge, use the {@link #getSmallIcon()} to
+     * represent this notification.
+     */
+    public static final int BADGE_ICON_SMALL = 1;
+
+    /**
+     * If this notification is being shown as a badge, use the {@link #getLargeIcon()} to
+     * represent this notification.
+     */
+    public static final int BADGE_ICON_LARGE = 2;
+    private int mBadgeIcon = BADGE_ICON_LARGE;
+
     /**
      * Structure to encapsulate a named action that can be shown as part of this notification.
      * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
@@ -1818,6 +1837,12 @@
             mChannelId = parcel.readString();
         }
         mTimeout = parcel.readLong();
+
+        if (parcel.readInt() != 0) {
+            mShortcutId = parcel.readString();
+        }
+
+        mBadgeIcon = parcel.readInt();
     }
 
     @Override
@@ -2042,7 +2067,7 @@
         }
         try {
             // IMPORTANT: Add marshaling code in writeToParcelImpl as we
-            // want to intercept all pending events written to the pacel.
+            // want to intercept all pending events written to the parcel.
             writeToParcelImpl(parcel, flags);
             // Must be written last!
             parcel.writeArraySet(allPendingIntents);
@@ -2185,6 +2210,15 @@
             parcel.writeInt(0);
         }
         parcel.writeLong(mTimeout);
+
+        if (mShortcutId != null) {
+            parcel.writeInt(1);
+            parcel.writeString(mShortcutId);
+        } else {
+            parcel.writeInt(0);
+        }
+
+        parcel.writeInt(mBadgeIcon);
     }
 
     /**
@@ -2382,13 +2416,30 @@
     }
 
     /**
-     * Returns the time at which this notification should be canceled, if it's not canceled already.
+     * Returns the time at which this notification should be canceled by the system, if it's not
+     * canceled already.
      */
     public long getTimeout() {
         return mTimeout;
     }
 
     /**
+     * Returns what icon should be shown for this notification if it is being displayed in a
+     * Launcher that supports badging. Will be one of {@link #BADGE_ICON_NONE},
+     * {@link #BADGE_ICON_SMALL}, or {@link #BADGE_ICON_LARGE}.
+     */
+    public int getBadgeIcon() {
+        return mBadgeIcon;
+    }
+
+    /**
+     * Returns the {@link ShortcutInfo#getId() id} that this notification supersedes, if any.
+     */
+    public String getShortcutId() {
+        return mShortcutId;
+    }
+
+    /**
      * The small icon representing this notification in the status bar and content view.
      *
      * @return the small icon representing this notification.
@@ -2483,7 +2534,6 @@
         private NotificationColorUtil mColorUtil;
         private boolean mIsLegacy;
         private boolean mIsLegacyInitialized;
-        private boolean mColorUtilInited = false;
 
         /**
          * Caches a contrast-enhanced version of {@link #mCachedContrastColorIsFor}.
@@ -2601,16 +2651,42 @@
         }
 
         private NotificationColorUtil getColorUtil() {
-            if (!mColorUtilInited) {
-                mColorUtilInited = true;
-                if (isLegacy() || isColorized()) {
-                    mColorUtil = NotificationColorUtil.getInstance(mContext);
-                }
+            if (mColorUtil == null) {
+                mColorUtil = NotificationColorUtil.getInstance(mContext);
             }
             return mColorUtil;
         }
 
         /**
+         * If this notification is duplicative of a Launcher shortcut, sets the
+         * {@link ShortcutInfo#getId() id} of the shortcut, in case the Launcher wants to hide
+         * the shortcut.
+         *
+         * This field will be ignored by Launchers that don't support badging or
+         * {@link android.content.pm.ShortcutManager shortcuts}.
+         *
+         * @param shortcutId the {@link ShortcutInfo#getId() id} of the shortcut this notification
+         *                   supersedes
+         */
+        public Builder setShortcutId(String shortcutId) {
+            mN.mShortcutId = shortcutId;
+            return this;
+        }
+
+        /**
+         * Sets which icon to display as a badge for this notification.
+         *
+         * Must be one of {@link #BADGE_ICON_NONE}, {@link #BADGE_ICON_SMALL},
+         * {@link #BADGE_ICON_LARGE}.
+         *
+         * Note: This value might be ignored, for launchers that don't support badge icons.
+         */
+        public Builder chooseBadgeIcon(int icon) {
+            mN.mBadgeIcon = icon;
+            return this;
+        }
+
+        /**
          * Specifies the channel the notification should be delivered on.
          */
         public Builder setChannel(String channelId) {
@@ -2805,13 +2881,9 @@
         }
 
         /**
-         * Set the large number at the right-hand side of the notification.  This is
-         * equivalent to setContentInfo, although it might show the number in a different
-         * font size for readability.
-         *
-         * @deprecated this number is not shown anywhere anymore
+         * Sets the number of items this notification represents. May be displayed as a badge count
+         * for Launchers that support badging.
          */
-        @Deprecated
         public Builder setNumber(int number) {
             mN.number = number;
             return this;
@@ -3055,7 +3127,7 @@
 
          * Not all devices will honor all (or even any) of these values.
          *
-         * @deprecated use {@link NotificationChannel#setLights(boolean)} instead.
+         * @deprecated use {@link NotificationChannel#enableLights(boolean)} instead.
          * @see Notification#ledARGB
          * @see Notification#ledOnMS
          * @see Notification#ledOffMS
@@ -3096,12 +3168,16 @@
          * Set whether this notification should be colorized. When set, the color set with
          * {@link #setColor(int)} will be used as the background color of this notification.
          * <p>
-         * The coloring will only be applied if the notification is ongoing.
          * This should only be used for high priority ongoing tasks like navigation, an ongoing
          * call, or other similarly high-priority events for the user.
+         * <p>
+         * For most styles, the coloring will only be applied if the notification is ongoing.
+         * However, for {@link MediaStyle} and {@link DecoratedMediaCustomViewStyle} notifications
+         * that have a media session attached there is no requirement for it to be ongoing.
          *
          * @see Builder#setOngoing(boolean)
          * @see Builder#setColor(int)
+         * @see MediaStyle#setMediaSession(MediaSession.Token)
          */
         public Builder setColorized(boolean colorize) {
             mN.extras.putBoolean(EXTRA_COLORIZED, colorize);
@@ -3150,7 +3226,7 @@
          * For all default values, use {@link #DEFAULT_ALL}.
          *
          * @deprecated use {@link NotificationChannel#enableVibration(boolean)} and
-         * {@link NotificationChannel#setLights(boolean)} and
+         * {@link NotificationChannel#enableLights(boolean)} and
          * {@link NotificationChannel#setSound(Uri, AudioAttributes)} instead.
          */
         @Deprecated
@@ -3682,13 +3758,21 @@
         }
 
         private void bindExpandButton(RemoteViews contentView) {
-            int color = isColorized() ? getPrimaryTextColor() : resolveContrastColor();
+            int color = getPrimaryHighlightColor();
             contentView.setDrawableParameters(R.id.expand_button, false, -1, color,
                     PorterDuff.Mode.SRC_ATOP, -1);
             contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
                     color);
         }
 
+        /**
+         * @return the color that is used as the first primary highlight color. This is applied
+         * in several places like the action buttons or the app name in the header.
+         */
+        private int getPrimaryHighlightColor() {
+            return isColorized() ? getPrimaryTextColor() : resolveContrastColor();
+        }
+
         private void bindHeaderChronometerAndTime(RemoteViews contentView) {
             if (showsTimeOrChronometer()) {
                 contentView.setViewVisibility(R.id.time_divider, View.VISIBLE);
@@ -4265,7 +4349,7 @@
         }
 
         private CharSequence processLegacyText(CharSequence charSequence) {
-            if (isLegacy() || isColorized()) {
+            if (isLegacy() || textColorsNeedInversion()) {
                 return getColorUtil().invertCharSequenceColors(charSequence);
             } else {
                 return charSequence;
@@ -4278,7 +4362,7 @@
         private void processSmallIconColor(Icon smallIcon, RemoteViews contentView,
                 boolean ambient) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
-            int color = ambient ? resolveAmbientColor() : resolveContrastColor();
+            int color = ambient ? resolveAmbientColor() : getPrimaryHighlightColor();
             if (colorable) {
                 contentView.setDrawableParameters(R.id.icon, false, -1, color,
                         PorterDuff.Mode.SRC_ATOP, -1);
@@ -4539,6 +4623,15 @@
         private boolean isColorized() {
             return mN.isColorized();
         }
+
+        private boolean textColorsNeedInversion() {
+            if (mStyle == null || !MediaStyle.class.equals(mStyle.getClass())) {
+                return false;
+            }
+            int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+            return targetSdkVersion > Build.VERSION_CODES.M
+                    && targetSdkVersion < Build.VERSION_CODES.O;
+        }
     }
 
     /**
@@ -4551,6 +4644,14 @@
     }
 
     /**
+     * @return whether this notification has a media session attached
+     * @hide
+     */
+    public boolean hasMediaSession() {
+        return extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null;
+    }
+
+    /**
      * @return the style class of this notification
      * @hide
      */
@@ -4564,12 +4665,23 @@
     }
 
     /**
-     * @return true if this notification is colorized. This also factors in wheather the
+     * @return true if this notification is colorized. This also factors in whether the
      * notification is ongoing.
      *
      * @hide
      */
     public boolean isColorized() {
+        Class<? extends Style> style = getNotificationStyle();
+        if (MediaStyle.class.equals(style)) {
+            Boolean colorized = (Boolean) extras.get(EXTRA_COLORIZED);
+            if ((colorized == null || colorized) && hasMediaSession()) {
+                return true;
+            }
+        } else if (DecoratedMediaCustomViewStyle.class.equals(style)) {
+            if (extras.getBoolean(EXTRA_COLORIZED) && hasMediaSession()) {
+                return true;
+            }
+        }
         return extras.getBoolean(EXTRA_COLORIZED) && isOngoing();
     }
 
@@ -5815,21 +5927,27 @@
      * shown as icon-only pushbuttons, suitable for transport controls. The Bitmap given to
      * {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap) setLargeIcon()} will be
      * treated as album artwork.
-     *
+     * <p>
      * Unlike the other styles provided here, MediaStyle can also modify the standard-size
      * {@link Notification#contentView}; by providing action indices to
      * {@link #setShowActionsInCompactView(int...)} you can promote up to 3 actions to be displayed
      * in the standard view alongside the usual content.
-     *
+     * <p>
      * Notifications created with MediaStyle will have their category set to
      * {@link Notification#CATEGORY_TRANSPORT CATEGORY_TRANSPORT} unless you set a different
      * category using {@link Notification.Builder#setCategory(String) setCategory()}.
-     *
+     * <p>
      * Finally, if you attach a {@link android.media.session.MediaSession.Token} using
      * {@link android.app.Notification.MediaStyle#setMediaSession(MediaSession.Token)},
      * the System UI can identify this as a notification representing an active media session
      * and respond accordingly (by showing album artwork in the lockscreen, for example).
      *
+     * <p>
+     * Starting at {@link android.os.Build.VERSION_CODES#O Android O} any notification that has a
+     * media session attached with {@link #setMediaSession(MediaSession.Token)} will be colorized.
+     * You can opt-out of this behavior by using {@link Notification.Builder#setColorized(boolean)}.
+     * <p>
+     *
      * To use this style with your Notification, feed it to
      * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
      * <pre class="prettyprint">
@@ -5844,6 +5962,7 @@
      * </pre>
      *
      * @see Notification#bigContentView
+     * @see Notification.Builder#setColorized(boolean)
      */
     public static class MediaStyle extends Style {
         static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
@@ -5981,7 +6100,7 @@
 
                     final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
                     final RemoteViews button = generateMediaActionButton(action,
-                            mBuilder.resolveContrastColor());
+                            getPrimaryHighlightColor());
                     view.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
@@ -5995,6 +6114,10 @@
             return view;
         }
 
+        private int getPrimaryHighlightColor() {
+            return mBuilder.getPrimaryHighlightColor();
+        }
+
         private RemoteViews makeMediaBigContentView() {
             final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
             // Dont add an expanded view if there is no more content to be revealed
@@ -6012,7 +6135,7 @@
                 big.removeAllViews(com.android.internal.R.id.media_actions);
                 for (int i = 0; i < actionCount; i++) {
                     final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i),
-                            mBuilder.resolveContrastColor());
+                            getPrimaryHighlightColor());
                     big.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
@@ -6157,7 +6280,10 @@
      * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
      * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
      * corresponding custom views to display.
-     *
+     * <p>
+     * Contrary to {@link MediaStyle} a developer has to opt-in to the colorizing of the
+     * notification by using {@link Notification.Builder#setColorized(boolean)}.
+     * <p>
      * To use this style with your Notification, feed it to
      * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
      * <pre class="prettyprint">
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index afcbcdf..1a51608 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -21,7 +21,7 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import android.annotation.SystemApi;
-import android.app.NotificationManager;
+import android.graphics.Color;
 import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.Parcel;
@@ -51,7 +51,6 @@
     private static final String ATT_VISIBILITY = "visibility";
     private static final String ATT_IMPORTANCE = "importance";
     private static final String ATT_LIGHTS = "lights";
-    //TODO: add support for light colors
     private static final String ATT_LIGHT_COLOR = "light_color";
     private static final String ATT_VIBRATION = "vibration";
     private static final String ATT_VIBRATION_ENABLED = "vibration_enabled";
@@ -129,7 +128,7 @@
             USER_LOCKED_AUDIO_ATTRIBUTES
     };
 
-
+    private static final int DEFAULT_LIGHT_COLOR = 0;
     private static final int DEFAULT_VISIBILITY =
             NotificationManager.VISIBILITY_NO_OVERRIDE;
     private static final int DEFAULT_IMPORTANCE =
@@ -144,6 +143,7 @@
     private int mLockscreenVisibility = DEFAULT_VISIBILITY;
     private Uri mSound;
     private boolean mLights;
+    private int mLightColor = DEFAULT_LIGHT_COLOR;
     private long[] mVibration;
     private int mUserLockedFields;
     private boolean mVibrationEnabled;
@@ -194,6 +194,7 @@
             mGroup = null;
         }
         mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
+        mLightColor = in.readInt();
     }
 
     @Override
@@ -232,6 +233,7 @@
         } else {
             dest.writeInt(0);
         }
+        dest.writeInt(mLightColor);
     }
 
     /**
@@ -331,11 +333,22 @@
      * Only modifiable before the channel is submitted to
      * {@link NotificationManager#notify(String, int, Notification)}.
      */
-    public void setLights(boolean lights) {
+    public void enableLights(boolean lights) {
         this.mLights = lights;
     }
 
     /**
+     * Sets the notification light color for notifications posted to this channel, if lights are
+     * {@link #enableLights(boolean) enabled} on this channel and the device supports that feature.
+     *
+     * Only modifiable before the channel is submitted to
+     * {@link NotificationManager#notify(String, int, Notification)}.
+     */
+    public void setLightColor(int argb) {
+        this.mLightColor = argb;
+    }
+
+    /**
      * Sets whether notification posted to this channel should vibrate. The vibration pattern can
      * be set with {@link #setVibrationPattern(long[])}.
      *
@@ -411,6 +424,14 @@
     }
 
     /**
+     * Returns the notification light color for notifications posted to this channel. Irrelevant
+     * unless {@link #shouldShowLights()}.
+     */
+    public int getLightColor() {
+        return mLightColor;
+    }
+
+    /**
      * Returns whether notifications posted to this channel always vibrate.
      */
     public boolean shouldVibrate() {
@@ -478,7 +499,8 @@
                 != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
         setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
         setSound(safeUri(parser, ATT_SOUND), safeAudioAttributes(parser));
-        setLights(safeBool(parser, ATT_LIGHTS, false));
+        enableLights(safeBool(parser, ATT_LIGHTS, false));
+        setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR));
         enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
         setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
         setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
@@ -519,6 +541,9 @@
         if (shouldShowLights()) {
             out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
         }
+        if (getLightColor() != DEFAULT_LIGHT_COLOR) {
+            out.attribute(null, ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
+        }
         if (shouldVibrate()) {
             out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
         }
@@ -569,6 +594,7 @@
             record.put(ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
         }
         record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
+        record.put(ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
         record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
         record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
         record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
@@ -669,6 +695,7 @@
         if (mBypassDnd != that.mBypassDnd) return false;
         if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
         if (mLights != that.mLights) return false;
+        if (getLightColor() != that.getLightColor()) return false;
         if (getUserLockedFields() != that.getUserLockedFields()) return false;
         if (mVibrationEnabled != that.mVibrationEnabled) return false;
         if (mShowBadge != that.mShowBadge) return false;
@@ -698,6 +725,7 @@
         result = 31 * result + getLockscreenVisibility();
         result = 31 * result + (getSound() != null ? getSound().hashCode() : 0);
         result = 31 * result + (mLights ? 1 : 0);
+        result = 31 * result + getLightColor();
         result = 31 * result + Arrays.hashCode(mVibration);
         result = 31 * result + getUserLockedFields();
         result = 31 * result + (mVibrationEnabled ? 1 : 0);
@@ -718,6 +746,7 @@
                 ", mLockscreenVisibility=" + mLockscreenVisibility +
                 ", mSound=" + mSound +
                 ", mLights=" + mLights +
+                ", mLightColor=" + mLightColor +
                 ", mVibration=" + Arrays.toString(mVibration) +
                 ", mUserLockedFields=" + mUserLockedFields +
                 ", mVibrationEnabled=" + mVibrationEnabled +
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 68cac27..8854adc 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -170,6 +170,11 @@
     }
 
     @Override
+    public NotificationChannelGroup clone() {
+        return new NotificationChannelGroup(getId(), getName());
+    }
+
+    @Override
     public int hashCode() {
         int result = getId() != null ? getId().hashCode() : 0;
         result = 31 * result + (getName() != null ? getName().hashCode() : 0);
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
index a37680f..5958bc1 100644
--- a/core/java/android/app/RemoteAction.java
+++ b/core/java/android/app/RemoteAction.java
@@ -35,55 +35,30 @@
  */
 public final class RemoteAction implements Parcelable {
 
-    /**
-     * Interface definition for a callback to be invoked when an action is invoked.
-     */
-    public interface OnActionListener {
-        /**
-         * Called when the associated action is invoked.
-         *
-         * @param action The action that was invoked.
-         */
-        void onAction(RemoteAction action);
-    }
-
     private static final String TAG = "RemoteAction";
 
-    private static final int MESSAGE_ACTION_INVOKED = 1;
-
     private final Icon mIcon;
     private final CharSequence mTitle;
     private final CharSequence mContentDescription;
-    private OnActionListener mActionCallback;
-    private final Messenger mMessenger;
+    private final PendingIntent mActionIntent;
 
     RemoteAction(Parcel in) {
         mIcon = Icon.CREATOR.createFromParcel(in);
         mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mMessenger = in.readParcelable(Messenger.class.getClassLoader());
+        mActionIntent = PendingIntent.CREATOR.createFromParcel(in);
     }
 
     public RemoteAction(@NonNull Icon icon, @NonNull CharSequence title,
-            @NonNull CharSequence contentDescription, @NonNull OnActionListener callback) {
-        if (icon == null || title == null || contentDescription == null || callback == null) {
+            @NonNull CharSequence contentDescription, @NonNull PendingIntent intent) {
+        if (icon == null || title == null || contentDescription == null || intent == null) {
             throw new IllegalArgumentException("Expected icon, title, content description and " +
                     "action callback");
         }
         mIcon = icon;
         mTitle = title;
         mContentDescription = contentDescription;
-        mActionCallback = callback;
-        mMessenger = new Messenger(new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case MESSAGE_ACTION_INVOKED:
-                        mActionCallback.onAction(RemoteAction.this);
-                        break;
-                }
-            }
-        });
+        mActionIntent = intent;
     }
 
     /**
@@ -108,22 +83,15 @@
     }
 
     /**
-     * Sends a message that the action was invoked.
-     * @hide
+     * Return the action intent.
      */
-    public void sendActionInvoked() {
-        Message m = Message.obtain();
-        m.what = MESSAGE_ACTION_INVOKED;
-        try {
-            mMessenger.send(m);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Could not send action-invoked", e);
-        }
+    public @NonNull PendingIntent getActionIntent() {
+        return mActionIntent;
     }
 
     @Override
     public RemoteAction clone() {
-        return new RemoteAction(mIcon, mTitle, mContentDescription, mActionCallback);
+        return new RemoteAction(mIcon, mTitle, mContentDescription, mActionIntent);
     }
 
     @Override
@@ -136,7 +104,7 @@
         mIcon.writeToParcel(out, 0);
         TextUtils.writeToParcel(mTitle, out, flags);
         TextUtils.writeToParcel(mContentDescription, out, flags);
-        out.writeParcelable(mMessenger, flags);
+        mActionIntent.writeToParcel(out, flags);
     }
 
     public void dump(String prefix, PrintWriter pw) {
@@ -144,6 +112,7 @@
         pw.print("title=" + mTitle);
         pw.print(" contentDescription=" + mContentDescription);
         pw.print(" icon=" + mIcon);
+        pw.print(" action=" + mActionIntent.getIntent());
         pw.println();
     }
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5a75a67..44db326 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -30,6 +30,8 @@
 import android.app.usage.UsageStatsManager;
 import android.appwidget.AppWidgetManager;
 import android.bluetooth.BluetoothManager;
+import android.companion.CompanionDeviceManager;
+import android.companion.ICompanionDeviceManager;
 import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.IRestrictionsManager;
@@ -115,6 +117,7 @@
 import android.service.autofill.IAutoFillManagerService;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
+import android.service.vr.IVrManager;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
@@ -633,6 +636,18 @@
                         UserHandle.getAppId(Process.myUid()));
             }});
 
+        registerService(Context.COMPANION_DEVICE_SERVICE, CompanionDeviceManager.class,
+                new CachedServiceFetcher<CompanionDeviceManager>() {
+                    @Override
+                    public CompanionDeviceManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder iBinder =
+                                ServiceManager.getServiceOrThrow(Context.COMPANION_DEVICE_SERVICE);
+                        ICompanionDeviceManager service =
+                                ICompanionDeviceManager.Stub.asInterface(iBinder);
+                        return new CompanionDeviceManager(service, ctx);
+                    }});
+
         registerService(Context.CONSUMER_IR_SERVICE, ConsumerIrManager.class,
                 new CachedServiceFetcher<ConsumerIrManager>() {
             @Override
@@ -814,6 +829,14 @@
                 IAutoFillManagerService service = IAutoFillManagerService.Stub.asInterface(b);
                 return new AutoFillManager(ctx, service);
             }});
+
+        registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
+            @Override
+            public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getServiceOrThrow(Context.VR_SERVICE);
+                return new VrManager(IVrManager.Stub.asInterface(b));
+            }
+        });
     }
 
     /**
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 3f467a0..b219f2a 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -145,14 +145,25 @@
     }
 
     @Override
+    public void show() {
+        super.show();
+        getButton(BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                if (mTimePicker.validateInput()) {
+                    if (mTimeSetListener != null) {
+                        mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
+                                mTimePicker.getCurrentMinute());
+                    }
+                    dismiss();
+                }
+            }
+        });
+    }
+
+    @Override
     public void onClick(DialogInterface dialog, int which) {
         switch (which) {
-            case BUTTON_POSITIVE:
-                if (mTimeSetListener != null) {
-                    mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
-                            mTimePicker.getCurrentMinute());
-                }
-                break;
             case BUTTON_NEGATIVE:
                 cancel();
                 break;
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 6d1d1a3..1d6f42e 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1118,6 +1118,16 @@
                 public void onFingerprintGesture(int gesture) {
                     /* do nothing */
                 }
+
+                @Override
+                public void onAccessibilityButtonClicked() {
+                    /* do nothing */
+                }
+
+                @Override
+                public void onAccessibilityButtonAvailabilityChanged(boolean available) {
+                    /* do nothing */
+                }
             });
         }
     }
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
new file mode 100644
index 0000000..a0b0eea
--- /dev/null
+++ b/core/java/android/app/VrManager.java
@@ -0,0 +1,44 @@
+package android.app;
+
+
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.service.vr.IVrManager;
+
+/**
+ * Used to control aspects of a devices Virtual Reality (VR) capabilities.
+ * <p>
+ * You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService}.
+ * @hide
+ */
+@SystemApi
+public class VrManager {
+    private final IVrManager mService;
+
+    /**
+     * {@hide}
+     */
+    public VrManager(IVrManager service) {
+        mService = service;
+    }
+
+    /**
+     * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
+     * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
+     * by VR viewers to indicate that a device is placed in a VR viewer.
+     *
+     * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
+     *
+     * @see Activity#setVrModeEnabled(boolean, ComponentName)
+     * @param enabled true if the device should be placed in persistent VR mode.
+     */
+    public void setPersistentVrModeEnabled(boolean enabled) {
+        try {
+            mService.setPersistentVrModeEnabled(enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 08832d1..f1ccabe 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -377,7 +377,7 @@
      * @hide
      */
     public static final String ACTION_BUGREPORT_SHARING_ACCEPTED =
-            "com.android.server.action.BUGREPORT_SHARING_ACCEPTED";
+            "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED";
 
     /**
      * Action: Bugreport sharing with device owner has been declined by the user.
@@ -385,7 +385,7 @@
      * @hide
      */
     public static final String ACTION_BUGREPORT_SHARING_DECLINED =
-            "com.android.server.action.BUGREPORT_SHARING_DECLINED";
+            "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED";
 
     /**
      * Action: Bugreport has been collected and is dispatched to {@code DevicePolicyManagerService}.
@@ -6108,8 +6108,6 @@
      * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of
      * an affiliated user or profile.
      * @see #setLockTaskPackages
-     *
-     * @hide
      */
     public @NonNull String[] getLockTaskPackages(@NonNull ComponentName admin) {
         throwIfParentInstance("getLockTaskPackages");
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 2858991..91b87d7 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -144,8 +144,7 @@
         }
 
         /**
-         * Returns the payload contained in this log. Each call to this method will
-         * retrieve the next payload item. If no more payload exists, it returns {@code null}.
+         * Returns the payload contained in this log entry or {@code null} if there is no payload.
          */
         public Object getData() {
             return mEvent.getData();
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 57f18f1..0874095 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -138,13 +138,13 @@
                     mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
         }
 
+        // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
+        // regards to their mEndTimeStamp.
         if (right.mBeginTimeStamp > mBeginTimeStamp) {
-            // The incoming UsageStat begins after this one, so use its last time used fields
-            // as the source of truth.
-            // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
-            // regards to their mEndTimeStamp.
-            mLastEvent = right.mLastEvent;
-            mLastTimeUsed = right.mLastTimeUsed;
+            // Even though incoming UsageStat begins after this one, its last time used fields
+            // may somehow be empty or chronologically preceding the older UsageStat.
+            mLastEvent = Math.max(mLastEvent, right.mLastEvent);
+            mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed);
         }
         mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
         mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index a482103..176e48f 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -37,9 +37,11 @@
     public static final int SOURCE_CODEC_TYPE_APTX    = 2;
     public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
     public static final int SOURCE_CODEC_TYPE_LDAC    = 4;
+    public static final int SOURCE_CODEC_TYPE_MAX     = 5;
 
     public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
 
+    public static final int CODEC_PRIORITY_DISABLED = -1;
     public static final int CODEC_PRIORITY_DEFAULT = 0;
     public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
 
@@ -72,7 +74,7 @@
 
     public BluetoothCodecConfig(int codecType, int codecPriority,
                                 int sampleRate, int bitsPerSample,
-                                int channelMode,long codecSpecific1,
+                                int channelMode, long codecSpecific1,
                                 long codecSpecific2, long codecSpecific3,
                                 long codecSpecific4) {
         mCodecType = codecType;
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 17a802d..b89c64a 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -67,7 +67,9 @@
     private final byte[] mManufacturerData;
     @Nullable
     private final byte[] mManufacturerDataMask;
-    private static final ScanFilter EMPTY = new ScanFilter.Builder().build() ;
+
+    /** @hide */
+    public static final ScanFilter EMPTY = new ScanFilter.Builder().build() ;
 
 
     private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
@@ -318,8 +320,12 @@
         return true;
     }
 
-    // Check if the uuid pattern is contained in a list of parcel uuids.
-    private boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask,
+    /**
+     * Check if the uuid pattern is contained in a list of parcel uuids.
+     *
+     * @hide
+     */
+    public static boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask,
             List<ParcelUuid> uuids) {
         if (uuid == null) {
             return true;
@@ -338,7 +344,7 @@
     }
 
     // Check if the uuid pattern matches the particular service uuid.
-    private boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
+    private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
         if (mask == null) {
             return uuid.equals(data);
         }
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/android/companion/AssociationRequest.aidl
similarity index 68%
copy from core/java/android/service/autofill/CallbackHelper.java
copy to core/java/android/companion/AssociationRequest.aidl
index ded8f97..6c91062 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/android/companion/AssociationRequest.aidl
@@ -13,18 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.autofill;
 
-import java.io.PrintWriter;
+package android.companion;
 
-final class CallbackHelper {
-
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
-
-    static interface Finalizer {
-        void gone();
-    }
-}
+parcelable AssociationRequest;
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
new file mode 100644
index 0000000..d477f43
--- /dev/null
+++ b/core/java/android/companion/AssociationRequest.java
@@ -0,0 +1,191 @@
+/*
+ * 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 android.companion;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.OneTimeUseBuilder;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A request for the user to select a companion device to associate with.
+ *
+ * You can optionally set a {@link Builder#setDeviceFilter filter} for which devices to show to the
+ * user to select from.
+ * The exact type and fields of the filter you can set depend on the
+ * medium type. See {@link Builder}'s static factory methods for specific protocols that are
+ * supported.
+ *
+ * You can also set {@link Builder#setSingleDevice single device} to request a popup with single
+ * device to be shown instead of a list to choose from
+ *
+ * @param <F> Device filter type
+ */
+public final class AssociationRequest<F extends DeviceFilter> implements Parcelable {
+
+    /** @hide */
+    public static final int MEDIUM_TYPE_BLUETOOTH = 0;
+    /** @hide */
+    public static final int MEDIUM_TYPE_BLUETOOTH_LE = 1;
+    /** @hide */
+    public static final int MEDIUM_TYPE_WIFI = 2;
+
+    /** @hide */
+    @IntDef({MEDIUM_TYPE_BLUETOOTH, MEDIUM_TYPE_BLUETOOTH_LE, MEDIUM_TYPE_WIFI})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediumType {}
+
+    private final boolean mSingleDevice;
+    private final int mMediumType;
+    private final F mDeviceFilter;
+
+    private AssociationRequest(boolean singleDevice, int mMediumType, F deviceFilter) {
+        this.mSingleDevice = singleDevice;
+        this.mMediumType = mMediumType;
+        this.mDeviceFilter = deviceFilter;
+    }
+
+    private AssociationRequest(Parcel in) {
+        this(
+            in.readByte() != 0,
+            in.readInt(),
+            in.readParcelable(AssociationRequest.class.getClassLoader()));
+    }
+
+    /** @hide */
+    public boolean isSingleDevice() {
+        return mSingleDevice;
+    }
+
+    /** @hide */
+    @MediumType
+    public int getMediumType() {
+        return mMediumType;
+    }
+
+    /** @hide */
+    @Nullable
+    public F getDeviceFilter() {
+        return mDeviceFilter;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByte((byte) (mSingleDevice ? 1 : 0));
+        dest.writeInt(mMediumType);
+        dest.writeParcelable(mDeviceFilter, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<AssociationRequest> CREATOR = new Creator<AssociationRequest>() {
+        @Override
+        public AssociationRequest createFromParcel(Parcel in) {
+            return new AssociationRequest(in);
+        }
+
+        @Override
+        public AssociationRequest[] newArray(int size) {
+            return new AssociationRequest[size];
+        }
+    };
+
+    /**
+     * A builder for {@link AssociationRequest}
+     *
+     * @param <F> the type of filter for the request.
+     */
+    public static final class Builder<F extends DeviceFilter>
+            extends OneTimeUseBuilder<AssociationRequest<F>> {
+        private boolean mSingleDevice = false;
+        @MediumType private int mMediumType;
+        @Nullable private F mDeviceFilter = null;
+
+        private Builder() {}
+
+        /**
+         * Create a new builder for an association request with a Bluetooth LE device
+         */
+        @NonNull
+        public static Builder<BluetoothLEDeviceFilter> createForBluetoothLEDevice() {
+            return new Builder<BluetoothLEDeviceFilter>()
+                    .setMediumType(MEDIUM_TYPE_BLUETOOTH_LE);
+        }
+
+        /**
+         * Create a new builder for an association request with a Bluetooth(non-LE) device
+         */
+        @NonNull
+        public static Builder<BluetoothDeviceFilter> createForBluetoothDevice() {
+            return new Builder<BluetoothDeviceFilter>()
+                    .setMediumType(MEDIUM_TYPE_BLUETOOTH);
+        }
+
+        //TODO implement, once specific filter classes are available
+//        public static Builder<> createForWiFiDevice()
+//        public static Builder<> createForNanDevice()
+
+        /**
+         * @param singleDevice if true, scanning for a device will stop as soon as at least one
+         *                     fitting device is found
+         */
+        @NonNull
+        public Builder<F> setSingleDevice(boolean singleDevice) {
+            checkNotUsed();
+            this.mSingleDevice = singleDevice;
+            return this;
+        }
+
+        /**
+         * @param deviceFilter if set, only devices matching the given filter will be shown to the
+         *                     user
+         */
+        @NonNull
+        public Builder<F> setDeviceFilter(@Nullable F deviceFilter) {
+            checkNotUsed();
+            this.mDeviceFilter = deviceFilter;
+            return this;
+        }
+
+        /**
+         * @param deviceType A type of medium over which to discover devices
+         *
+         * @see MediumType
+         */
+        @NonNull
+        private Builder<F> setMediumType(@MediumType int deviceType) {
+            mMediumType = deviceType;
+            return this;
+        }
+
+        /** @inheritDoc */
+        @NonNull
+        @Override
+        public AssociationRequest<F> build() {
+            markUsed();
+            return new AssociationRequest<>(mSingleDevice, mMediumType, mDeviceFilter);
+        }
+    }
+}
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
new file mode 100644
index 0000000..5a69955
--- /dev/null
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -0,0 +1,202 @@
+/*
+ * 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 android.companion;
+
+import static android.companion.BluetoothDeviceFilterUtils.matchesAddress;
+import static android.companion.BluetoothDeviceFilterUtils.matchesName;
+import static android.companion.BluetoothDeviceFilterUtils.matchesServiceUuids;
+import static android.companion.BluetoothDeviceFilterUtils.patternFromString;
+import static android.companion.BluetoothDeviceFilterUtils.patternToString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.provider.OneTimeUseBuilder;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * A filter for Bluetooth(non-LE) devices
+ */
+public final class BluetoothDeviceFilter implements DeviceFilter<BluetoothDevice> {
+
+    private static BluetoothDeviceFilter NO_OP;
+
+    private final Pattern mNamePattern;
+    private final String mAddress;
+    private final List<ParcelUuid> mServiceUuids;
+    private final List<ParcelUuid> mServiceUuidMasks;
+
+    private BluetoothDeviceFilter(
+            Pattern namePattern,
+            String address,
+            List<ParcelUuid> serviceUuids,
+            List<ParcelUuid> serviceUuidMasks) {
+        mNamePattern = namePattern;
+        mAddress = address;
+        mServiceUuids = ArrayUtils.emptyIfNull(serviceUuids);
+        mServiceUuidMasks = ArrayUtils.emptyIfNull(serviceUuidMasks);
+    }
+
+    private BluetoothDeviceFilter(Parcel in) {
+        this(
+            patternFromString(in.readString()),
+            in.readString(),
+            readUuids(in),
+            readUuids(in));
+    }
+
+    private static List<ParcelUuid> readUuids(Parcel in) {
+        final ArrayList<ParcelUuid> list = new ArrayList<>();
+        in.readParcelableList(list, ParcelUuid.class.getClassLoader());
+        return list;
+    }
+
+    /** @hide */
+    @NonNull
+    public static BluetoothDeviceFilter nullsafe(@Nullable BluetoothDeviceFilter nullable) {
+        return nullable != null ? nullable : noOp();
+    }
+
+    /** @hide */
+    @NonNull
+    public static BluetoothDeviceFilter noOp() {
+        if (NO_OP == null) NO_OP = new Builder().build();
+        return NO_OP;
+    }
+
+    /** @hide */
+    @Override
+    public boolean matches(BluetoothDevice device) {
+        return matchesAddress(mAddress, device)
+                && matchesServiceUuids(mServiceUuids, mServiceUuidMasks, device)
+                && matchesName(getNamePattern(), device);
+    }
+
+    /** @hide */
+    @Nullable
+    public Pattern getNamePattern() {
+        return mNamePattern;
+    }
+
+    /** @hide */
+    @Nullable
+    public String getAddress() {
+        return mAddress;
+    }
+
+    /** @hide */
+    @NonNull
+    public List<ParcelUuid> getServiceUuids() {
+        return mServiceUuids;
+    }
+
+    /** @hide */
+    @NonNull
+    public List<ParcelUuid> getServiceUuidMasks() {
+        return mServiceUuidMasks;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(patternToString(getNamePattern()));
+        dest.writeString(mAddress);
+        dest.writeParcelableList(mServiceUuids, flags);
+        dest.writeParcelableList(mServiceUuidMasks, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<BluetoothDeviceFilter> CREATOR
+            = new Creator<BluetoothDeviceFilter>() {
+        @Override
+        public BluetoothDeviceFilter createFromParcel(Parcel in) {
+            return new BluetoothDeviceFilter(in);
+        }
+
+        @Override
+        public BluetoothDeviceFilter[] newArray(int size) {
+            return new BluetoothDeviceFilter[size];
+        }
+    };
+
+    /**
+     * A builder for {@link BluetoothDeviceFilter}
+     */
+    public static final class Builder extends OneTimeUseBuilder<BluetoothDeviceFilter> {
+        private Pattern mNamePattern;
+        private String mAddress;
+        private ArrayList<ParcelUuid> mServiceUuid;
+        private ArrayList<ParcelUuid> mServiceUuidMask;
+
+        /**
+         * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
+         *              given regular expression will be shown
+         */
+        public Builder setNamePattern(@Nullable Pattern regex) {
+            checkNotUsed();
+            mNamePattern = regex;
+            return this;
+        }
+
+        /**
+         * @param address if set, only devices with MAC address exactly matching the given one will
+         *                pass the filter
+         */
+        @NonNull
+        public Builder setAddress(@Nullable String address) {
+            checkNotUsed();
+            mAddress = address;
+            return this;
+        }
+
+        /**
+         * Add filtering by certain bits of {@link BluetoothDevice#getUuids()}
+         *
+         * A device with any uuid matching the given bits is considered passing
+         *
+         * @param serviceUuid the values for the bits to match
+         * @param serviceUuidMask if provided, only those bits would have to match.
+         */
+        @NonNull
+        public Builder addServiceUuid(
+                @Nullable ParcelUuid serviceUuid, @Nullable ParcelUuid serviceUuidMask) {
+            checkNotUsed();
+            mServiceUuid = ArrayUtils.add(mServiceUuid, serviceUuid);
+            mServiceUuidMask = ArrayUtils.add(mServiceUuidMask, serviceUuidMask);
+            return this;
+        }
+
+        /** @inheritDoc */
+        @Override
+        @NonNull
+        public BluetoothDeviceFilter build() {
+            markUsed();
+            return new BluetoothDeviceFilter(
+                    mNamePattern, mAddress, mServiceUuid, mServiceUuidMask);
+        }
+    }
+}
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
new file mode 100644
index 0000000..289f995
--- /dev/null
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -0,0 +1,107 @@
+/*
+ * 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 android.companion;
+
+import static android.text.TextUtils.firstNotEmpty;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.ScanFilter;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/** @hide */
+public class BluetoothDeviceFilterUtils {
+    private BluetoothDeviceFilterUtils() {}
+
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "BluetoothDeviceFilterUtil";
+
+    @Nullable
+    static String patternToString(@Nullable Pattern p) {
+        return p == null ? null : p.pattern();
+    }
+
+    @Nullable
+    static Pattern patternFromString(@Nullable String s) {
+        return s == null ? null : Pattern.compile(s);
+    }
+
+    static boolean matches(ScanFilter filter, BluetoothDevice device) {
+        return matchesAddress(filter.getDeviceAddress(), device)
+                && matchesServiceUuid(filter.getServiceUuid(), filter.getServiceUuidMask(), device);
+    }
+
+    static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
+        final boolean result = deviceAddress == null
+                || (device == null || !deviceAddress.equals(device.getAddress()));
+        if (DEBUG) debugLogMatchResult(result, device, deviceAddress);
+        return result;
+    }
+
+    static boolean matchesServiceUuids(List<ParcelUuid> serviceUuids,
+            List<ParcelUuid> serviceUuidMasks, BluetoothDevice device) {
+        for (int i = 0; i < serviceUuids.size(); i++) {
+            ParcelUuid uuid = serviceUuids.get(i);
+            ParcelUuid uuidMask = serviceUuidMasks.get(i);
+            if (!matchesServiceUuid(uuid, uuidMask, device)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    static boolean matchesServiceUuid(ParcelUuid serviceUuid, ParcelUuid serviceUuidMask,
+            BluetoothDevice device) {
+        final boolean result = serviceUuid == null ||
+                ScanFilter.matchesServiceUuids(
+                        serviceUuid,
+                        serviceUuidMask,
+                        Arrays.asList(device.getUuids()));
+        if (DEBUG) debugLogMatchResult(result, device, serviceUuid);
+        return result;
+    }
+
+    static boolean matchesName(@Nullable Pattern namePattern, BluetoothDevice device) {
+        boolean result;
+        if (namePattern == null)  {
+            result = true;
+        } else if (device == null) {
+            result = false;
+        } else {
+            final String name = device.getName();
+            result = name != null && namePattern.matcher(name).find();
+        }
+        if (DEBUG) debugLogMatchResult(result, device, namePattern);
+        return result;
+    }
+
+    private static void debugLogMatchResult(
+            boolean result, BluetoothDevice device, Object criteria) {
+        Log.i(LOG_TAG, getDeviceDisplayName(device) + (result ? " ~ " : " !~ ") + criteria);
+    }
+
+    public static String getDeviceDisplayName(@NonNull BluetoothDevice device) {
+        return firstNotEmpty(device.getAliasName(), device.getAddress());
+    }
+}
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/android/companion/BluetoothLEDeviceFilter.aidl
similarity index 68%
copy from core/java/android/service/autofill/CallbackHelper.java
copy to core/java/android/companion/BluetoothLEDeviceFilter.aidl
index ded8f97..628cf7b 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.aidl
@@ -13,18 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.autofill;
 
-import java.io.PrintWriter;
+package android.companion;
 
-final class CallbackHelper {
-
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
-
-    static interface Finalizer {
-        void gone();
-    }
-}
+parcelable BluetoothLEDeviceFilter;
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
new file mode 100644
index 0000000..4a481ca
--- /dev/null
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -0,0 +1,151 @@
+/*
+ * 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 android.companion;
+
+import static android.companion.BluetoothDeviceFilterUtils.patternFromString;
+import static android.companion.BluetoothDeviceFilterUtils.patternToString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.ScanFilter;
+import android.os.Parcel;
+import android.provider.OneTimeUseBuilder;
+
+import com.android.internal.util.ObjectUtils;
+
+import java.util.regex.Pattern;
+
+/**
+ * A filter for Bluetooth LE devices
+ *
+ * @see ScanFilter
+ */
+public final class BluetoothLEDeviceFilter implements DeviceFilter<BluetoothDevice> {
+
+    private static BluetoothLEDeviceFilter NO_OP;
+
+    private final Pattern mNamePattern;
+    private final ScanFilter mScanFilter;
+
+    private BluetoothLEDeviceFilter(Pattern namePattern, ScanFilter scanFilter) {
+        mNamePattern = namePattern;
+        mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY);
+    }
+
+    @SuppressLint("ParcelClassLoader")
+    private BluetoothLEDeviceFilter(Parcel in) {
+        this(
+            patternFromString(in.readString()),
+            in.readParcelable(null));
+    }
+
+    /** @hide */
+    @NonNull
+    public static BluetoothLEDeviceFilter nullsafe(@Nullable BluetoothLEDeviceFilter nullable) {
+        return nullable != null ? nullable : noOp();
+    }
+
+    /** @hide */
+    @NonNull
+    public static BluetoothLEDeviceFilter noOp() {
+        if (NO_OP == null) NO_OP = new Builder().build();
+        return NO_OP;
+    }
+
+    /** @hide */
+    @Nullable
+    public Pattern getNamePattern() {
+        return mNamePattern;
+    }
+
+    /** @hide */
+    @NonNull
+    public ScanFilter getScanFilter() {
+        return mScanFilter;
+    }
+
+    /** @hide */
+    @Override
+    public boolean matches(BluetoothDevice device) {
+        return BluetoothDeviceFilterUtils.matches(getScanFilter(), device)
+                && BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(patternToString(getNamePattern()));
+        dest.writeParcelable(mScanFilter, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<BluetoothLEDeviceFilter> CREATOR
+            = new Creator<BluetoothLEDeviceFilter>() {
+        @Override
+        public BluetoothLEDeviceFilter createFromParcel(Parcel in) {
+            return new BluetoothLEDeviceFilter(in);
+        }
+
+        @Override
+        public BluetoothLEDeviceFilter[] newArray(int size) {
+            return new BluetoothLEDeviceFilter[size];
+        }
+    };
+
+    /**
+     * Builder for {@link BluetoothLEDeviceFilter}
+     */
+    public static final class Builder extends OneTimeUseBuilder<BluetoothLEDeviceFilter> {
+        private ScanFilter mScanFilter;
+        private Pattern mNamePattern;
+
+        /**
+         * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
+         *              given regular expression will be shown
+         */
+        public Builder setNamePattern(@Nullable Pattern regex) {
+            checkNotUsed();
+            mNamePattern = regex;
+            return this;
+        }
+
+        /**
+         * @param scanFilter a {@link ScanFilter} to filter devices by
+         *
+         * @see ScanFilter for specific details on its various fields
+         */
+        @NonNull
+        public Builder setScanFilter(@Nullable ScanFilter scanFilter) {
+            checkNotUsed();
+            mScanFilter = scanFilter;
+            return this;
+        }
+
+        /** @inheritDoc */
+        @Override
+        @NonNull
+        public BluetoothLEDeviceFilter build() {
+            markUsed();
+            return new BluetoothLEDeviceFilter(mNamePattern, mScanFilter);
+        }
+    }
+}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
new file mode 100644
index 0000000..b379c7c
--- /dev/null
+++ b/core/java/android/companion/CompanionDeviceManager.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 android.companion;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.IntentSender;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+
+/**
+ * System level service for managing companion devices
+ *
+ * Usage:
+ * To obtain an instance call
+ * {@link Context#getSystemService}({@link Context#COMPANION_DEVICE_SERVICE})
+ *
+ * Then, call {@link #associate} to initiate the flow of associating current package
+ * with a device selected by user
+ *
+ * @see AssociationRequest
+ */
+public final class CompanionDeviceManager {
+
+    /**
+     * A device, returned in the activity result of the {@link IntentSender} received in
+     * {@link Callback#onDeviceFound}
+     */
+    public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+
+    /**
+     * A callback to receive once at least one suitable device is found, or the search failed
+     * (e.g. timed out)
+     */
+    public abstract static class Callback {
+
+        /**
+         * Called once at least one suitable device is found
+         *
+         * @param chooserLauncher a {@link IntentSender} to launch the UI for user to select a
+         *                        device
+         */
+        public abstract void onDeviceFound(IntentSender chooserLauncher);
+
+        /**
+         * Called if there was an error looking for device(s), e.g. timeout
+         *
+         * @param error the cause of the error
+         */
+        public abstract void onFailure(CharSequence error);
+    }
+
+    private final ICompanionDeviceManager mService;
+    private final Context mContext;
+
+    /** @hide */
+    public CompanionDeviceManager(
+            @NonNull ICompanionDeviceManager service, @NonNull Context context) {
+        mService = service;
+        mContext = context;
+    }
+
+    /**
+     * Associate this app with a companion device, selected by user
+     *
+     * Once at least one appropriate device is found, {@code callback} will be called with a
+     * {@link PendingIntent} that can be used to show the list of available devices for the user
+     * to select.
+     * It should be started for result (i.e. using
+     * {@link android.app.Activity#startIntentSenderForResult}), as the resulting
+     * {@link android.content.Intent} will contain extra {@link #EXTRA_DEVICE}, with the selected
+     * device. (e.g. {@link android.bluetooth.BluetoothDevice})
+     *
+     * @param request specific details about this request
+     * @param callback will be called once there's at least one device found for user to choose from
+     * @param handler A handler to control which thread the callback will be delivered on, or null,
+     *                to deliver it on main thread
+     *
+     * @see AssociationRequest
+     */
+    public void associate(
+            @NonNull AssociationRequest<?> request,
+            @NonNull Callback callback,
+            @Nullable Handler handler) {
+        final Handler finalHandler = handler != null
+                ? handler
+                : new Handler(Looper.getMainLooper());
+        try {
+            mService.associate(
+                    request,
+                    new IOnAssociateCallback.Stub() {
+
+                        @Override
+                        public void onSuccess(PendingIntent launcher) throws RemoteException {
+                            finalHandler.post(() -> {
+                                callback.onDeviceFound(launcher.getIntentSender());
+                            });
+                        }
+
+                        @Override
+                        public void onFailure(CharSequence reason) throws RemoteException {
+                            finalHandler.post(() -> callback.onFailure(reason));
+                        }
+                    },
+                    mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public void requestNotificationAccess() {
+        //TODO implement
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /** @hide */
+    public boolean haveNotificationAccess() {
+        //TODO implement
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+}
diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java
new file mode 100644
index 0000000..8362b2d
--- /dev/null
+++ b/core/java/android/companion/DeviceFilter.java
@@ -0,0 +1,46 @@
+/*
+ * 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 android.companion;
+
+import android.annotation.Nullable;
+import android.os.Parcelable;
+
+/**
+ * A filter for companion devices of type {@code D}
+ *
+ * @param <D> Type of devices, filtered by this filter,
+ *           e.g. {@link android.bluetooth.BluetoothDevice}, {@link android.net.wifi.WifiInfo}
+ */
+public interface DeviceFilter<D extends Parcelable> extends Parcelable {
+
+    /**
+     * @return whether the given device matches this filter
+     *
+     * @hide
+     */
+    boolean matches(D device);
+
+    /**
+     * A nullsafe {@link #matches(Parcelable)}, returning true if the filter is null
+     *
+     * @hide
+     */
+    static <D extends Parcelable> boolean matches(@Nullable DeviceFilter<D> filter, D device) {
+        return filter == null || filter.matches(device);
+    }
+}
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
new file mode 100644
index 0000000..065e31b
--- /dev/null
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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 android.companion;
+
+import android.companion.IOnAssociateCallback;
+import android.companion.AssociationRequest;
+
+/**
+ * Interface for communication with the core companion device manager service.
+ *
+ * @hide
+ */
+interface ICompanionDeviceManager {
+    void associate(in AssociationRequest request,
+        in IOnAssociateCallback callback,
+        in String callingPackage); //TODO int userId?
+
+    //TODO add these
+//    boolean haveNotificationAccess(String packageName);
+//    oneway void requestNotificationAccess(String packageName);
+}
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/android/companion/ICompanionDeviceManagerService.aidl
similarity index 65%
copy from core/java/android/service/autofill/CallbackHelper.java
copy to core/java/android/companion/ICompanionDeviceManagerService.aidl
index ded8f97..ff2a7eb 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/android/companion/ICompanionDeviceManagerService.aidl
@@ -13,18 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.autofill;
 
-import java.io.PrintWriter;
+package android.companion;
 
-final class CallbackHelper {
+import android.companion.AssociationRequest;
+import android.companion.IOnAssociateCallback;
 
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
 
-    static interface Finalizer {
-        void gone();
-    }
+/** @hide */
+interface ICompanionDeviceManagerService {
+    void startDiscovery(
+        in AssociationRequest request,
+        in IOnAssociateCallback callback,
+        in String callingPackage);
 }
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
similarity index 60%
copy from core/java/android/service/autofill/CallbackHelper.java
copy to core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
index ded8f97..c9dd345 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
@@ -10,21 +10,15 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
+ * See the License for the specific language governing per  missions and
  * limitations under the License.
  */
-package android.service.autofill;
 
-import java.io.PrintWriter;
+package android.companion;
 
-final class CallbackHelper {
+import android.bluetooth.BluetoothDevice;
 
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
-
-    static interface Finalizer {
-        void gone();
-    }
+/** @hide */
+interface ICompanionDeviceManagerServiceCallback {
+    void onDeviceSelected(in BluetoothDevice device);
 }
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/android/companion/IOnAssociateCallback.aidl
similarity index 60%
copy from core/java/android/service/autofill/CallbackHelper.java
copy to core/java/android/companion/IOnAssociateCallback.aidl
index ded8f97..4867eadd 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/android/companion/IOnAssociateCallback.aidl
@@ -10,21 +10,16 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
+ * See the License for the specific language governing per  missions and
  * limitations under the License.
  */
-package android.service.autofill;
 
-import java.io.PrintWriter;
+package android.companion;
 
-final class CallbackHelper {
+import android.app.PendingIntent;
 
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
-
-    static interface Finalizer {
-        void gone();
-    }
+/** @hide */
+interface IOnAssociateCallback {
+    void onSuccess(in PendingIntent launcher);
+    void onFailure(in CharSequence reason);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f610a29..06f7303 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -35,6 +35,7 @@
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.Notification;
+import android.app.VrManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -3599,6 +3600,14 @@
     public static final String PRINT_SERVICE = "print";
 
     /**
+     * {@link android.companion.CompanionDeviceManager} for managing companion devices
+     *
+     * @see #getSystemService
+     * @see android.companion.CompanionDeviceManager
+     */
+    public static final String COMPANION_DEVICE_SERVICE = "companion_device";
+
+    /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.hardware.ConsumerIrManager} for transmitting infrared
      * signals from the device.
@@ -3764,6 +3773,16 @@
     public static final String OVERLAY_SERVICE = "overlay";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link VrManager} for accessing the VR service.
+     *
+     * @see #getSystemService
+     * @hide
+     */
+    @SystemApi
+    public static final String VR_SERVICE = "vrmanager";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1130327..5f4c36c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1806,6 +1806,41 @@
     @SystemApi
     public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
 
+    /**
+     * Intent extra: An id if an autofill item ({@link
+     * android.view.autofill.Dataset} or {@link android.view.autofill.FillResponse}).
+     * <p>
+     * Type: String
+     * </p>
+     */
+    public static final String EXTRA_AUTO_FILL_ITEM_ID = "android.intent.extra.AUTO_FILL_ITEM_ID";
+
+    /**
+     * Intent extra: The assist structure which captures the filled screen.
+     * <p>
+     * Type: {@link android.app.assist.AssistStructure}
+     * </p>
+     */
+    public static final String EXTRA_AUTO_FILL_ASSIST_STRUCTURE =
+            "android.intent.extra.AUTO_FILL_ASSIST_STRUCTURE";
+
+    /**
+     * Intent extra: The metadata associated with the authenticated entity ({@link
+     * android.view.autofill.Dataset} or {@link android.view.autofill.FillResponse}).
+     * <p>
+     * Type: {@link android.os.Bundle}
+     * </p>
+     */
+    public static final String EXTRA_AUTO_FILL_EXTRAS = "android.intent.extra.AUTO_FILL_EXTRAS";
+
+    /**
+     * Intent extra: A callback to report an authentication result.
+     * <p>
+     * Type: {@link android.view.autofill.FillResponse}
+     * </p>
+     */
+    public static final String EXTRA_AUTO_FILL_CALLBACK = "android.intent.extra.AUTO_FILL_CALLBACK";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent broadcast actions (see action variable).
@@ -6004,6 +6039,12 @@
                 case "--receiver-foreground":
                     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                     break;
+                case "--receiver-no-abort":
+                    intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
+                    break;
+                case "--receiver-include-background":
+                    intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+                    break;
                 case "--selector":
                     intent.setDataAndType(data, type);
                     intent = new Intent();
@@ -6127,7 +6168,8 @@
                 "    [--activity-single-top] [--activity-clear-task]",
                 "    [--activity-task-on-home]",
                 "    [--receiver-registered-only] [--receiver-replace-pending]",
-                "    [--receiver-foreground]",
+                "    [--receiver-foreground] [--receiver-no-abort]",
+                "    [--receiver-include-background]",
                 "    [--selector]",
                 "    [<URI> | <PACKAGE> | <COMPONENT>]"
         };
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index dd53eac..74d2f11 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -351,7 +351,7 @@
          * @param requiresCharging true if sync requires the phone to be plugged in. Default false.
          */
         public Builder setRequiresCharging(boolean requiresCharging) {
-            mRequiresCharging = true;
+            mRequiresCharging = requiresCharging;
             return this;
         }
 
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 92cb709..9a8eff0 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -397,14 +397,6 @@
     public static final int FLAG_ALWAYS_FOCUSABLE = 0x40000;
 
     /**
-     * Bit in {@link #flags} indicating if the activity is a launcher activity which should always
-     * show up on the top of others.
-     * See android.R.attr#onTopLauncher.
-     * @hide
-     */
-    public static final int FLAG_ON_TOP_LAUNCHER = 0x80000;
-
-    /**
      * Bit in {@link #flags} indicating if the activity is visible to ephemeral applications.
      * @hide
      */
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index a135d8f..59c5307 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -34,6 +34,13 @@
     public String targetPackage;
 
     /**
+     * Names of the process(es) this instrumentation will run in.  If not specified, only
+     * runs in the main process of the targetPackage.  Can either be a comma-separated list
+     * of process names or '*' for any process that launches to run targetPackage code.
+     */
+    public String targetProcess;
+
+    /**
      * Full path to the base APK for this application.
      */
     public String sourceDir;
@@ -113,6 +120,7 @@
     public InstrumentationInfo(InstrumentationInfo orig) {
         super(orig);
         targetPackage = orig.targetPackage;
+        targetProcess = orig.targetProcess;
         sourceDir = orig.sourceDir;
         publicSourceDir = orig.publicSourceDir;
         splitNames = orig.splitNames;
@@ -141,6 +149,7 @@
     public void writeToParcel(Parcel dest, int parcelableFlags) {
         super.writeToParcel(dest, parcelableFlags);
         dest.writeString(targetPackage);
+        dest.writeString(targetProcess);
         dest.writeString(sourceDir);
         dest.writeString(publicSourceDir);
         dest.writeStringArray(splitNames);
@@ -170,6 +179,7 @@
     private InstrumentationInfo(Parcel source) {
         super(source);
         targetPackage = source.readString();
+        targetProcess = source.readString();
         sourceDir = source.readString();
         publicSourceDir = source.readString();
         splitNames = source.readStringArray();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ab641c9..b20b5e2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1741,6 +1741,22 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan native API
+     * will enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate
+     * what level of optional compute features are supported beyond the Vulkan 1.0 requirements.
+     * <p>
+     * Compute level 0 indicates support for:
+     * <ul>
+     * <li>Ability to use pointers to buffer data from shaders</li>
+     * <li>Ability to load/store 16-bit values from buffers</li>
+     * <li>Ability to control shader floating point rounding mode</li>
+     * </ul>
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature(String, int)}: The version of this feature indicates the highest
      * {@code VkPhysicalDeviceProperties::apiVersion} supported by the physical devices that support
      * the hardware level indicated by {@link #FEATURE_VULKAN_HARDWARE_LEVEL}. The feature version
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ff928a0..7cef781 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -17,7 +17,6 @@
 package android.content.pm;
 
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
 import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -1623,6 +1622,7 @@
             return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);
 
         } catch (XmlPullParserException | IOException | RuntimeException e) {
+            Slog.w(TAG, "Failed to parse " + apkPath, e);
             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                     "Failed to parse " + apkPath, e);
         } finally {
@@ -3160,6 +3160,10 @@
                 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
         a.info.targetPackage = str != null ? str.intern() : null;
 
+        str = sa.getNonResourceString(
+                com.android.internal.R.styleable.AndroidManifestInstrumentation_targetProcess);
+        a.info.targetProcess = str != null ? str.intern() : null;
+
         a.info.handleProfiling = sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
                 false);
@@ -4105,10 +4109,6 @@
                 a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
             }
 
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_onTopLauncher, false)) {
-                a.info.flags |= FLAG_ON_TOP_LAUNCHER;
-            }
-
             a.info.lockTaskLaunchMode =
                     sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
 
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 3cf36d7..bf81096 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -753,7 +753,7 @@
         }
 
         final String file = value.string.toString();
-        Typeface cached = Typeface.createFromCache(mAssets, file);
+        Typeface cached = Typeface.findFromCache(mAssets, file);
         if (cached != null) {
             return cached;
         }
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 522575f..d951294 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -259,10 +259,6 @@
             throw new IllegalArgumentException("Unknow surface source class type");
         }
 
-        if (surfaceSize.getWidth() == 0 || surfaceSize.getHeight() == 0) {
-            throw new IllegalArgumentException("Surface size needs to be non-zero");
-        }
-
         mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
         mSurfaces = new ArrayList<Surface>();
         mRotation = ROTATION_0;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 3eb5844..98a5749 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -230,9 +230,6 @@
         public int dozeScreenBrightness;
         public int dozeScreenState;
 
-        // If true, use twilight to affect the brightness.
-        public boolean useTwilight;
-
         public DisplayPowerRequest() {
             policy = POLICY_BRIGHT;
             useProximitySensor = false;
@@ -268,7 +265,6 @@
             boostScreenBrightness = other.boostScreenBrightness;
             dozeScreenBrightness = other.dozeScreenBrightness;
             dozeScreenState = other.dozeScreenState;
-            useTwilight = other.useTwilight;
         }
 
         @Override
@@ -289,8 +285,7 @@
                     && lowPowerMode == other.lowPowerMode
                     && boostScreenBrightness == other.boostScreenBrightness
                     && dozeScreenBrightness == other.dozeScreenBrightness
-                    && dozeScreenState == other.dozeScreenState
-                    && useTwilight == other.useTwilight;
+                    && dozeScreenState == other.dozeScreenState;
         }
 
         @Override
@@ -310,8 +305,7 @@
                     + ", lowPowerMode=" + lowPowerMode
                     + ", boostScreenBrightness=" + boostScreenBrightness
                     + ", dozeScreenBrightness=" + dozeScreenBrightness
-                    + ", dozeScreenState=" + Display.stateToString(dozeScreenState)
-                    + ", useTwilight=" + useTwilight;
+                    + ", dozeScreenState=" + Display.stateToString(dozeScreenState);
         }
 
         public static String policyToString(int policy) {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 2c9e6c7..7947620 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -766,7 +766,7 @@
 
     /**
      * Retrieves the authenticator token for binding keys to the lifecycle
-     * of the current set of fingerprints. Used only by internal clients.
+     * of the calling user's fingerprints. Used only by internal clients.
      *
      * @hide
      */
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5996fe2..5ae1fd0 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -387,8 +387,9 @@
             mInputConnection = binding.getConnection();
             if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
                     + " ic=" + mInputConnection);
-            InputConnection ic = getCurrentInputConnection();
-            if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
+            if (mImm != null && mToken != null) {
+                mImm.reportFullscreenMode(mToken, mIsFullscreen);
+            }
             initialize();
             onBindInput();
         }
@@ -1027,8 +1028,9 @@
         if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
             changed = true;
             mIsFullscreen = isFullscreen;
-            InputConnection ic = getCurrentInputConnection();
-            if (ic != null) ic.reportFullscreenMode(isFullscreen);
+            if (mImm != null && mToken != null) {
+                mImm.reportFullscreenMode(mToken, mIsFullscreen);
+            }
             mFullscreenApplied = true;
             initialize();
             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 82432c7..9cc256e 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -18,6 +18,7 @@
 
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
+import android.net.NetworkScorerAppManager;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -130,4 +131,6 @@
      */
     oneway void requestRecommendationAsync(in RecommendationRequest request,
                                            in RemoteCallback remoteCallback);
+
+    NetworkScorerAppManager.NetworkScorerAppData getActiveScorer();
 }
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 57cf1a5..2875580 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -186,6 +186,20 @@
     }
 
     /**
+     * Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
+     *
+     * @hide
+     */
+    @Nullable
+    public NetworkScorerAppData getActiveScorer() {
+        try {
+            return mService.getActiveScorer();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Update network scores.
      *
      * <p>This may be called at any time to re-score active networks. Scores will generally be
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/net/NetworkScorerAppManager.aidl
new file mode 100644
index 0000000..d968343
--- /dev/null
+++ b/core/java/android/net/NetworkScorerAppManager.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.net;
+
+parcelable NetworkScorerAppManager.NetworkScorerAppData;
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 9e4dd87..f3cbb52 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -18,11 +18,14 @@
 
 import android.Manifest.permission;
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -33,6 +36,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Internal class for discovering and managing the network scorer/recommendation application.
@@ -52,34 +56,73 @@
     /**
      * Holds metadata about a discovered network scorer/recommendation application.
      */
-    public static class NetworkScorerAppData {
-        /** Package name of this scorer app. */
-        public final String packageName;
-
+    public static final class NetworkScorerAppData implements Parcelable {
         /** UID of the scorer app. */
         public final int packageUid;
+        private final ComponentName mRecommendationService;
 
-        /**
-         * Name of the recommendation service we can bind to.
-         */
-        public final String recommendationServiceClassName;
-
-        public NetworkScorerAppData(String packageName, int packageUid,
-                String recommendationServiceClassName) {
-            this.packageName = packageName;
+        public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp) {
             this.packageUid = packageUid;
-            this.recommendationServiceClassName = recommendationServiceClassName;
+            this.mRecommendationService = recommendationServiceComp;
+        }
+
+        protected NetworkScorerAppData(Parcel in) {
+            packageUid = in.readInt();
+            mRecommendationService = ComponentName.readFromParcel(in);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(packageUid);
+            ComponentName.writeToParcel(mRecommendationService, dest);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<NetworkScorerAppData> CREATOR =
+                new Creator<NetworkScorerAppData>() {
+                    @Override
+                    public NetworkScorerAppData createFromParcel(Parcel in) {
+                        return new NetworkScorerAppData(in);
+                    }
+
+                    @Override
+                    public NetworkScorerAppData[] newArray(int size) {
+                        return new NetworkScorerAppData[size];
+                    }
+                };
+
+        public String getRecommendationServicePackageName() {
+            return mRecommendationService.getPackageName();
+        }
+
+        public ComponentName getRecommendationServiceComponent() {
+            return mRecommendationService;
         }
 
         @Override
         public String toString() {
-            final StringBuilder sb = new StringBuilder("NetworkScorerAppData{");
-            sb.append("mPackageName='").append(packageName).append('\'');
-            sb.append(", packageUid=").append(packageUid);
-            sb.append(", recommendationServiceClassName='")
-                    .append(recommendationServiceClassName).append('\'');
-            sb.append('}');
-            return sb.toString();
+            return "NetworkScorerAppData{" +
+                    "packageUid=" + packageUid +
+                    ", mRecommendationService=" + mRecommendationService +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            NetworkScorerAppData that = (NetworkScorerAppData) o;
+            return packageUid == that.packageUid &&
+                    Objects.equals(mRecommendationService, that.mRecommendationService);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(packageUid, mRecommendationService);
         }
     }
 
@@ -110,16 +153,16 @@
             return null;
         }
 
-        final PackageManager pm = mContext.getPackageManager();
         for (int i = 0; i < potentialPkgs.size(); i++) {
             final String potentialPkg = potentialPkgs.get(i);
 
             // Look for the recommendation service class and required receiver.
             final ResolveInfo resolveServiceInfo = findRecommendationService(potentialPkg);
             if (resolveServiceInfo != null) {
-                return new NetworkScorerAppData(potentialPkg,
-                    resolveServiceInfo.serviceInfo.applicationInfo.uid,
-                    resolveServiceInfo.serviceInfo.name);
+                final ComponentName componentName =
+                        new ComponentName(potentialPkg, resolveServiceInfo.serviceInfo.name);
+                return new NetworkScorerAppData(resolveServiceInfo.serviceInfo.applicationInfo.uid,
+                        componentName);
             } else {
                 if (DEBUG) {
                     Log.d(TAG, potentialPkg + " does not have the required components, skipping.");
diff --git a/core/java/android/net/RecommendationRequest.java b/core/java/android/net/RecommendationRequest.java
index b89a245..9f97c5a 100644
--- a/core/java/android/net/RecommendationRequest.java
+++ b/core/java/android/net/RecommendationRequest.java
@@ -50,7 +50,7 @@
         private WifiConfiguration mDefaultConfig;
         private WifiConfiguration mConnectedConfig;
         private WifiConfiguration[] mConnectableConfigs;
-        private int mLastSelectedNetworkId;
+        private int mLastSelectedNetworkId = -1;
         private long mLastSelectedTimestamp;
 
         public Builder setScanResults(ScanResult[] scanResults) {
@@ -161,7 +161,7 @@
 
     /**
      * @return The {@link WifiConfiguration#networkId} of the last user selected network.
-     *         {@code 0} if not set.
+     *         {@code -1} if not set.
      */
     public int getLastSelectedNetworkId() {
         return mLastSelectedNetworkId;
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index d396b50..ba0a8b5 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -106,7 +106,7 @@
      * the Network Recommendation Provider.
      *
      * @see #ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL
-     * @see #ATTRIBUTES_KEY_RANKING_SCORE_OFFSET_KEY
+     * @see #ATTRIBUTES_KEY_RANKING_SCORE_OFFSET
      */
     @Nullable
     public final Bundle attributes;
diff --git a/core/java/android/net/WifiKey.java b/core/java/android/net/WifiKey.java
index 99de99e..68b505d 100644
--- a/core/java/android/net/WifiKey.java
+++ b/core/java/android/net/WifiKey.java
@@ -64,10 +64,10 @@
      * @throws IllegalArgumentException if either the SSID or BSSID is invalid.
      */
     public WifiKey(String ssid, String bssid) {
-        if (!SSID_PATTERN.matcher(ssid).matches()) {
+        if (ssid == null || !SSID_PATTERN.matcher(ssid).matches()) {
             throw new IllegalArgumentException("Invalid ssid: " + ssid);
         }
-        if (!BSSID_PATTERN.matcher(bssid).matches()) {
+        if (bssid == null || !BSSID_PATTERN.matcher(bssid).matches()) {
             throw new IllegalArgumentException("Invalid bssid: " + bssid);
         }
         this.ssid = ssid;
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 263750a..3a441c7 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -201,6 +201,11 @@
      */
     public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
 
+    /**
+     * Battery charge status, from a BATTERY_STATUS_* value.
+     */
+    public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6;
+
     private final IBatteryStats mBatteryStats;
     private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 210ddb6..e05bd89 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2219,11 +2219,13 @@
     }
 
     /**
-     * Have the stack traces of the given native process dumped to the
-     * specified file.  Will be appended to the file.
+     * Append the stack traces of a given native process to a specified file.
+     * @param pid pid to dump.
+     * @param file path of file to append dump to.
+     * @param timeoutSecs time to wait in seconds, or 0 to wait forever.
      * @hide
      */
-    public static native void dumpNativeBacktraceToFile(int pid, String file);
+    public static native void dumpNativeBacktraceToFileTimeout(int pid, String file, int timeoutSecs);
 
     /**
      * Get description of unreachable native memory.
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index e99d303..f94e89a 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.IntegerRes;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -1339,7 +1340,7 @@
     }
 
     /**
-     * Flatten a heterogeneous array containing a particular object type into
+     * Flatten a homogeneous array containing a particular object type into
      * the parcel, at
      * the current dataPosition() and growing dataCapacity() if needed.  The
      * type of the objects in the array must be one that implements Parcelable.
@@ -1361,7 +1362,7 @@
         if (val != null) {
             int N = val.length;
             writeInt(N);
-            for (int i=0; i<N; i++) {
+            for (int i = 0; i < N; i++) {
                 T item = val[i];
                 if (item != null) {
                     writeInt(1);
@@ -1376,6 +1377,146 @@
     }
 
     /**
+     * Write a uniform (all items are null or the same class) array list of
+     * parcelables.
+     *
+     * @param list The list to write.
+     *
+     * @hide
+     */
+    public final <T extends Parcelable> void writeTypedArrayList(@Nullable ArrayList<T> list,
+            int parcelableFlags) {
+        if (list != null) {
+            int N = list.size();
+            writeInt(N);
+            boolean wroteCreator = false;
+            for (int i = 0; i < N; i++) {
+                T item = list.get(i);
+                if (item != null) {
+                    writeInt(1);
+                    if (!wroteCreator) {
+                        writeParcelableCreator(item);
+                        wroteCreator = true;
+                    }
+                    item.writeToParcel(this, parcelableFlags);
+                } else {
+                    writeInt(0);
+                }
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    /**
+     * Reads a uniform (all items are null or the same class) array list of
+     * parcelables.
+     *
+     * @return The list or null.
+     *
+     * @hide
+     */
+    public final @Nullable <T> ArrayList<T> readTypedArrayList(@Nullable ClassLoader loader) {
+        int N = readInt();
+        if (N <= 0) {
+            return null;
+        }
+        Parcelable.Creator<?> creator = null;
+        ArrayList<T> result = new ArrayList<T>(N);
+        for (int i = 0; i < N; i++) {
+            if (readInt() != 0) {
+                if (creator == null) {
+                    creator = readParcelableCreator(loader);
+                    if (creator == null) {
+                        return null;
+                    }
+                }
+                final T parcelable;
+                if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+                    Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+                            (Parcelable.ClassLoaderCreator<?>) creator;
+                    parcelable = (T) classLoaderCreator.createFromParcel(this, loader);
+                } else {
+                    parcelable = (T) creator.createFromParcel(this);
+                }
+                result.add(parcelable);
+            } else {
+                result.add(null);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Write a uniform (all items are null or the same class) array set of
+     * parcelables.
+     *
+     * @param set The set to write.
+     *
+     * @hide
+     */
+    public final <T extends Parcelable> void writeTypedArraySet(@Nullable ArraySet<T> set,
+            int parcelableFlags) {
+        if (set != null) {
+            int N = set.size();
+            writeInt(N);
+            boolean wroteCreator = false;
+            for (int i = 0; i < N; i++) {
+                T item = set.valueAt(i);
+                if (item != null) {
+                    writeInt(1);
+                    if (!wroteCreator) {
+                        writeParcelableCreator(item);
+                        wroteCreator = true;
+                    }
+                    item.writeToParcel(this, parcelableFlags);
+                } else {
+                    writeInt(0);
+                }
+            }
+        } else {
+            writeInt(-1);
+        }
+    }
+
+    /**
+     * Reads a uniform (all items are null or the same class) array set of
+     * parcelables.
+     *
+     * @return The set or null.
+     *
+     * @hide
+     */
+    public final @Nullable <T> ArraySet<T> readTypedArraySet(@Nullable ClassLoader loader) {
+        int N = readInt();
+        if (N <= 0) {
+            return null;
+        }
+        Parcelable.Creator<?> creator = null;
+        ArraySet<T> result = new ArraySet<T>(N);
+        for (int i = 0; i < N; i++) {
+            T parcelable = null;
+            if (readInt() != 0) {
+                if (creator == null) {
+                    creator = readParcelableCreator(loader);
+                    if (creator == null) {
+                        return null;
+                    }
+                }
+                if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+                    Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+                            (Parcelable.ClassLoaderCreator<?>) creator;
+                    parcelable = (T) classLoaderCreator.createFromParcel(this, loader);
+                } else {
+                    parcelable = (T) creator.createFromParcel(this);
+                }
+            }
+            result.append(parcelable);
+        }
+        return result;
+    }
+
+    /**
      * Flatten the Parcelable object into the parcel.
      *
      * @param val The Parcelable object to be written.
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index dff0a28..31b3bc9 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -508,15 +508,6 @@
     }
 
     /**
-     * Returns true if the twilight service should be used to adjust screen brightness
-     * policy.  This setting is experimental and disabled by default.
-     * @hide
-     */
-    public static boolean useTwilightAdjustmentFeature() {
-        return SystemProperties.getBoolean("persist.power.usetwilightadj", false);
-    }
-
-    /**
      * Creates a new wake lock with the specified level and flags.
      * <p>
      * The {@code levelAndFlags} parameter specifies a wake lock level and optional flags
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 06666f4..5e7f68b 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.animation.LayoutTransition;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.XmlRes;
@@ -87,7 +88,7 @@
  * items.  Doing this implicitly switches the class into its new "headers
  * + fragments" mode rather than the old style of just showing a single
  * preferences list.
- * 
+ *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For information about using {@code PreferenceActivity},
@@ -199,6 +200,9 @@
 
     private ViewGroup mPrefsContainer;
 
+    // Null if in legacy mode.
+    private ViewGroup mHeadersContainer;
+
     private FragmentBreadCrumbs mFragmentBreadCrumbs;
 
     private boolean mSinglePane;
@@ -292,7 +296,7 @@
                 holder = (HeaderViewHolder) view.getTag();
             }
 
-            // All view fields must be updated every time, because the view may be recycled 
+            // All view fields must be updated every time, because the view may be recycled
             Header header = getItem(position);
             if (mRemoveIconIfEmpty) {
                 if (header.iconRes == 0) {
@@ -469,7 +473,7 @@
             }
             return breadCrumbShortTitle;
         }
-        
+
         @Override
         public int describeContents() {
             return 0;
@@ -558,6 +562,7 @@
 
         mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
         mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame);
+        mHeadersContainer = (ViewGroup) findViewById(com.android.internal.R.id.headers);
         boolean hidingHeaders = onIsHidingHeaders();
         mSinglePane = hidingHeaders || !onIsMultiPane();
         String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
@@ -575,66 +580,39 @@
                         (int) HEADER_ID_UNDEFINED);
                 if (curHeader >= 0 && curHeader < mHeaders.size()) {
                     setSelectedHeader(mHeaders.get(curHeader));
+                } else if (!mSinglePane && initialFragment == null) {
+                    switchToHeader(onGetInitialHeader());
                 }
+            } else {
+                // This will for instance hide breadcrumbs for single pane.
+                showBreadCrumbs(getTitle(), null);
+            }
+        } else {
+            if (!onIsHidingHeaders()) {
+                onBuildHeaders(mHeaders);
             }
 
-        } else {
-            if (initialFragment != null && mSinglePane) {
-                // If we are just showing a fragment, we want to run in
-                // new fragment mode, but don't need to compute and show
-                // the headers.
+            if (initialFragment != null) {
                 switchToHeader(initialFragment, initialArguments);
-                if (initialTitle != 0) {
-                    CharSequence initialTitleStr = getText(initialTitle);
-                    CharSequence initialShortTitleStr = initialShortTitle != 0
-                            ? getText(initialShortTitle) : null;
-                    showBreadCrumbs(initialTitleStr, initialShortTitleStr);
-                }
-
-            } else {
-                // We need to try to build the headers.
-                onBuildHeaders(mHeaders);
-
-                // If there are headers, then at this point we need to show
-                // them and, depending on the screen, we may also show in-line
-                // the currently selected preference fragment.
-                if (mHeaders.size() > 0) {
-                    if (!mSinglePane) {
-                        if (initialFragment == null) {
-                            Header h = onGetInitialHeader();
-                            switchToHeader(h);
-                        } else {
-                            switchToHeader(initialFragment, initialArguments);
-                        }
-                    }
-                }
+            } else if (!mSinglePane && mHeaders.size() > 0) {
+                switchToHeader(onGetInitialHeader());
             }
         }
 
-        // The default configuration is to only show the list view.  Adjust
-        // visibility for other configurations.
-        if (initialFragment != null && mSinglePane) {
-            // Single pane, showing just a prefs fragment.
-            findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
-            mPrefsContainer.setVisibility(View.VISIBLE);
-            if (initialTitle != 0) {
-                CharSequence initialTitleStr = getText(initialTitle);
-                CharSequence initialShortTitleStr = initialShortTitle != 0
-                        ? getText(initialShortTitle) : null;
-                showBreadCrumbs(initialTitleStr, initialShortTitleStr);
-            }
-        } else if (mHeaders.size() > 0) {
+        if (mHeaders.size() > 0) {
             setListAdapter(new HeaderAdapter(this, mHeaders, mPreferenceHeaderItemResId,
                     mPreferenceHeaderRemoveEmptyIcon));
-            if (!mSinglePane) {
-                // Multi-pane.
-                getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
-                if (mCurHeader != null) {
-                    setSelectedHeader(mCurHeader);
-                }
-                mPrefsContainer.setVisibility(View.VISIBLE);
-            }
-        } else {
+            getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
+        }
+
+        if (mSinglePane && initialFragment != null && initialTitle != 0) {
+            CharSequence initialTitleStr = getText(initialTitle);
+            CharSequence initialShortTitleStr = initialShortTitle != 0
+                    ? getText(initialShortTitle) : null;
+            showBreadCrumbs(initialTitleStr, initialShortTitleStr);
+        }
+
+        if (mHeaders.size() == 0 && initialFragment == null) {
             // If there are no headers, we are in the old "just show a screen
             // of preferences" mode.
             setContentView(com.android.internal.R.layout.preference_list_content_single);
@@ -642,6 +620,25 @@
             mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs);
             mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
             mPreferenceManager.setOnPreferenceTreeClickListener(this);
+            mHeadersContainer = null;
+        } else if (mSinglePane) {
+            // Single-pane so one of the header or prefs containers must be hidden.
+            if (initialFragment != null || mCurHeader != null) {
+                mHeadersContainer.setVisibility(View.GONE);
+            } else {
+                mPrefsContainer.setVisibility(View.GONE);
+            }
+
+            // This animates our manual transitions between headers and prefs panel in single-pane.
+            // It also comes last so we don't animate any initial layout changes done above.
+            ViewGroup container = (ViewGroup) findViewById(
+                    com.android.internal.R.id.prefs_container);
+            container.setLayoutTransition(new LayoutTransition());
+        } else {
+            // Multi-pane
+            if (mHeaders.size() > 0 && mCurHeader != null) {
+                setSelectedHeader(mCurHeader);
+            }
         }
 
         // see if we should show Back/Next buttons
@@ -697,12 +694,25 @@
         }
     }
 
+    @Override
+    public void onBackPressed() {
+        if (mCurHeader != null && mSinglePane && getFragmentManager().getBackStackEntryCount() == 0
+                && getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT) == null) {
+            mCurHeader = null;
+
+            mPrefsContainer.setVisibility(View.GONE);
+            mHeadersContainer.setVisibility(View.VISIBLE);
+            getListView().clearChoices();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
     /**
      * Returns true if this activity is currently showing the header list.
      */
     public boolean hasHeaders() {
-        return getListView().getVisibility() == View.VISIBLE
-                && mPreferenceManager == null;
+        return mHeadersContainer != null && mHeadersContainer.getVisibility() == View.VISIBLE;
     }
 
     /**
@@ -718,7 +728,7 @@
      * and a preference fragment.
      */
     public boolean isMultiPane() {
-        return hasHeaders() && mPrefsContainer.getVisibility() == View.VISIBLE;
+        return !mSinglePane;
     }
 
     /**
@@ -820,14 +830,14 @@
             if (!"preference-headers".equals(nodeName)) {
                 throw new RuntimeException(
                         "XML document must start with <preference-headers> tag; found"
-                        + nodeName + " at " + parser.getPositionDescription());
+                                + nodeName + " at " + parser.getPositionDescription());
             }
 
             Bundle curBundle = null;
 
             final int outerDepth = parser.getDepth();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                     continue;
                 }
@@ -889,7 +899,7 @@
 
                     final int innerDepth = parser.getDepth();
                     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                           && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+                            && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
                         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                             continue;
                         }
@@ -939,8 +949,9 @@
         if (getApplicationInfo().targetSdkVersion  >= android.os.Build.VERSION_CODES.KITKAT) {
             throw new RuntimeException(
                     "Subclasses of PreferenceActivity must override isValidFragment(String)"
-                    + " to verify that the Fragment class is valid! " + this.getClass().getName()
-                    + " has not checked if fragment " + fragmentName + " is valid.");
+                            + " to verify that the Fragment class is valid! "
+                            + this.getClass().getName()
+                            + " has not checked if fragment " + fragmentName + " is valid.");
         } else {
             return true;
         }
@@ -1017,6 +1028,13 @@
         // Only call this if we didn't save the instance state for later.
         // If we did save it, it will be restored when we bind the adapter.
         super.onRestoreInstanceState(state);
+
+        if (!mSinglePane) {
+            // Multi-pane.
+            if (mCurHeader != null) {
+                setSelectedHeader(mCurHeader);
+            }
+        }
     }
 
     @Override
@@ -1061,18 +1079,7 @@
      */
     public void onHeaderClick(Header header, int position) {
         if (header.fragment != null) {
-            if (mSinglePane) {
-                int titleRes = header.breadCrumbTitleRes;
-                int shortTitleRes = header.breadCrumbShortTitleRes;
-                if (titleRes == 0) {
-                    titleRes = header.titleRes;
-                    shortTitleRes = 0;
-                }
-                startWithFragment(header.fragment, header.fragmentArguments, null, 0,
-                        titleRes, shortTitleRes);
-            } else {
-                switchToHeader(header);
-            }
+            switchToHeader(header);
         } else if (header.intent != null) {
             startActivity(header.intent);
         }
@@ -1084,7 +1091,7 @@
      * the selected fragment.  The default implementation constructs an Intent
      * that re-launches the current activity with the appropriate arguments to
      * display the fragment.
-     * 
+     *
      * @param fragmentName The name of the fragment to display.
      * @param args Optional arguments to supply to the fragment.
      * @param titleRes Optional resource ID of title to show for this item.
@@ -1103,7 +1110,7 @@
         intent.putExtra(EXTRA_NO_HEADERS, true);
         return intent;
     }
-    
+
     /**
      * Like {@link #startWithFragment(String, Bundle, Fragment, int, int, int)}
      * but uses a 0 titleRes.
@@ -1223,11 +1230,21 @@
             throw new IllegalArgumentException("Invalid fragment for this activity: "
                     + fragmentName);
         }
+
         Fragment f = Fragment.instantiate(this, fragmentName, args);
         FragmentTransaction transaction = getFragmentManager().beginTransaction();
-        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+        transaction.setTransition(mSinglePane
+                ? FragmentTransaction.TRANSIT_NONE
+                : FragmentTransaction.TRANSIT_FRAGMENT_FADE);
         transaction.replace(com.android.internal.R.id.prefs, f);
         transaction.commitAllowingStateLoss();
+
+        if (mSinglePane && mPrefsContainer.getVisibility() == View.GONE) {
+            // We are transitioning from headers to preferences panel in single-pane so we need
+            // to hide headers and show the prefs container.
+            mPrefsContainer.setVisibility(View.VISIBLE);
+            mHeadersContainer.setVisibility(View.GONE);
+        }
     }
 
     /**
@@ -1340,7 +1357,7 @@
      * be instantiated and placed in the appropriate pane.  If running in
      * single-pane mode, a new activity will be launched in which to show the
      * fragment.
-     * 
+     *
      * @param fragmentClass Full name of the class implementing the fragment.
      * @param args Any desired arguments to supply to the fragment.
      * @param titleRes Optional resource identifier of the title of this
@@ -1355,29 +1372,25 @@
      */
     public void startPreferencePanel(String fragmentClass, Bundle args, @StringRes int titleRes,
             CharSequence titleText, Fragment resultTo, int resultRequestCode) {
-        if (mSinglePane) {
-            startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0);
-        } else {
-            Fragment f = Fragment.instantiate(this, fragmentClass, args);
-            if (resultTo != null) {
-                f.setTargetFragment(resultTo, resultRequestCode);
-            }
-            FragmentTransaction transaction = getFragmentManager().beginTransaction();
-            transaction.replace(com.android.internal.R.id.prefs, f);
-            if (titleRes != 0) {
-                transaction.setBreadCrumbTitle(titleRes);
-            } else if (titleText != null) {
-                transaction.setBreadCrumbTitle(titleText);
-            }
-            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
-            transaction.addToBackStack(BACK_STACK_PREFS);
-            transaction.commitAllowingStateLoss();
+        Fragment f = Fragment.instantiate(this, fragmentClass, args);
+        if (resultTo != null) {
+            f.setTargetFragment(resultTo, resultRequestCode);
         }
+        FragmentTransaction transaction = getFragmentManager().beginTransaction();
+        transaction.replace(com.android.internal.R.id.prefs, f);
+        if (titleRes != 0) {
+            transaction.setBreadCrumbTitle(titleRes);
+        } else if (titleText != null) {
+            transaction.setBreadCrumbTitle(titleText);
+        }
+        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+        transaction.addToBackStack(BACK_STACK_PREFS);
+        transaction.commitAllowingStateLoss();
     }
 
     /**
      * Called by a preference panel fragment to finish itself.
-     * 
+     *
      * @param caller The fragment that is asking to be finished.
      * @param resultCode Optional result code to send back to the original
      * launching fragment.
@@ -1385,21 +1398,16 @@
      * launching fragment.
      */
     public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
-        if (mSinglePane) {
-            setResult(resultCode, resultData);
-            finish();
-        } else {
-            // XXX be smarter about popping the stack.
-            onBackPressed();
-            if (caller != null) {
-                if (caller.getTargetFragment() != null) {
-                    caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
-                            resultCode, resultData);
-                }
+        // TODO: be smarter about popping the stack.
+        onBackPressed();
+        if (caller != null) {
+            if (caller.getTargetFragment() != null) {
+                caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
+                        resultCode, resultData);
             }
         }
     }
-    
+
     @Override
     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
         startPreferencePanel(pref.getFragment(), pref.getExtras(), pref.getTitleRes(),
diff --git a/core/java/android/provider/OneTimeUseBuilder.java b/core/java/android/provider/OneTimeUseBuilder.java
new file mode 100644
index 0000000..682e9c7
--- /dev/null
+++ b/core/java/android/provider/OneTimeUseBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * 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 android.provider;
+
+/**
+ * A builder that facilitates prohibiting its use after an instance was created with it.
+ *
+ * Suggested usage:
+ * call {@link #checkNotUsed} in each setter, and {@link #markUsed} in {@link #build}
+ *
+ * @param <T> Type of object being built
+ * @hide
+ */
+public abstract class OneTimeUseBuilder<T> {
+    private boolean used = false;
+
+    protected void markUsed() {
+        checkNotUsed();
+        used = true;
+    }
+
+    protected void checkNotUsed() {
+        if (used) {
+            throw new IllegalStateException(
+                    "This Builder should not be reused. Use a new Builder instance instead");
+        }
+    }
+
+    /**
+     * Builds the instance
+     *
+     * Once this method is called, this builder should no longer be used. Any subsequent calls to a
+     * setter or {@code build()} will throw an exception
+     */
+    public abstract T build();
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d83f2cb..8b8edac 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -48,6 +48,7 @@
 import android.database.SQLException;
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
+import android.net.NetworkScoreManager;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
@@ -6721,12 +6722,6 @@
         public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
 
         /**
-         * Whether brightness should automatically adjust based on twilight state.
-         * @hide
-         */
-        public static final String BRIGHTNESS_USE_TWILIGHT = "brightness_use_twilight";
-
-        /**
          * Names of the service components that the current user has explicitly allowed to
          * be a VR mode listener, separated by ':'.
          *
@@ -6831,39 +6826,6 @@
                 "system_navigation_keys_enabled";
 
         /**
-         * Whether Downloads folder backup is enabled and should run on the device.
-         *
-         * @hide
-         */
-        public static final String DOWNLOADS_BACKUP_ENABLED = "downloads_backup_enabled";
-
-        /**
-         * Whether Downloads folder backup should only occur if the device is using a metered
-         * network.
-         *
-         * @hide
-         */
-        public static final String DOWNLOADS_BACKUP_ALLOW_METERED =
-                "downloads_backup_allow_metered";
-
-        /**
-         * Whether Downloads folder backup should only occur if the device is charging.
-         *
-         * @hide
-         */
-        public static final String DOWNLOADS_BACKUP_CHARGING_ONLY =
-                "downloads_backup_charging_only";
-
-        /**
-         * How many days of information for the automatic storage manager to retain on the device
-         * for downloads.
-         *
-         * @hide
-         */
-        public static final String AUTOMATIC_STORAGE_MANAGER_DOWNLOADS_DAYS_TO_RETAIN =
-                "automatic_storage_manager_downloads_days_to_retain";
-
-        /**
          * Holds comma separated list of ordering of QS tiles.
          * @hide
          */
@@ -8226,6 +8188,19 @@
                 "network_recommendations_enabled";
 
         /**
+         * Which package name to use for network recommendations. If null, network recommendations
+         * will neither be requested nor accepted.
+         *
+         * Use {@link NetworkScoreManager#getActiveScorerPackage()} to read this value and
+         * {@link NetworkScoreManager#setActiveScorer(String)} to write it.
+         *
+         * Type: string - package name
+         * @hide
+         */
+        public static final String NETWORK_RECOMMENDATIONS_PACKAGE =
+                "network_recommendations_package";
+
+        /**
          * Value to specify if the Wi-Fi Framework should defer to
          * {@link com.android.server.NetworkScoreService} for evaluating saved open networks.
          *
diff --git a/core/java/android/provider/SettingsStringUtil.java b/core/java/android/provider/SettingsStringUtil.java
new file mode 100644
index 0000000..f242d79
--- /dev/null
+++ b/core/java/android/provider/SettingsStringUtil.java
@@ -0,0 +1,174 @@
+/*
+ * 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 android.provider;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.text.TextUtils;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.function.Function;
+
+/**
+ * Utilities for dealing with {@link String} values in {@link Settings}
+ *
+ * @hide
+ */
+public class SettingsStringUtil {
+    private SettingsStringUtil() {}
+
+    public static final String DELIMITER = ":";
+
+    /**
+     * A {@link HashSet} of items, that uses a common convention of setting string
+     * serialization/deserialization of separating multiple items with {@link #DELIMITER}
+     */
+    public static abstract class ColonDelimitedSet<T> extends HashSet<T> {
+
+        public ColonDelimitedSet(String colonSeparatedItems) {
+            for (String cn :
+                    TextUtils.split(TextUtils.emptyIfNull(colonSeparatedItems), DELIMITER)) {
+                add(itemFromString(cn));
+            }
+        }
+
+        protected abstract T itemFromString(String s);
+        protected String itemToString(T item) {
+            return String.valueOf(item);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            Iterator<T> it = iterator();
+            if (it.hasNext()) {
+                sb.append(it.next());
+                while (it.hasNext()) {
+                    sb.append(DELIMITER);
+                    sb.append(itemToString(it.next()));
+                }
+            }
+            return sb.toString();
+        }
+
+
+        public static class OfStrings extends ColonDelimitedSet<String> {
+            public OfStrings(String colonSeparatedItems) {
+                super(colonSeparatedItems);
+            }
+
+            @Override
+            protected String itemFromString(String s) {
+                return s;
+            }
+
+            public static String add(String delimitedElements, String element) {
+                final ColonDelimitedSet<String> set
+                        = new ColonDelimitedSet.OfStrings(delimitedElements);
+                if (set.contains(element)) {
+                    return delimitedElements;
+                }
+                set.add(element);
+                return set.toString();
+            }
+
+            public static String remove(String delimitedElements, String element) {
+                final ColonDelimitedSet<String> set
+                        = new ColonDelimitedSet.OfStrings(delimitedElements);
+                if (!set.contains(element)) {
+                    return delimitedElements;
+                }
+                set.remove(element);
+                return set.toString();
+            }
+
+            public static boolean contains(String delimitedElements, String element) {
+                final String[] elements = TextUtils.split(delimitedElements, DELIMITER);
+                return ArrayUtils.indexOf(elements, element) != -1;
+            }
+        }
+    }
+
+    public static class ComponentNameSet extends ColonDelimitedSet<ComponentName> {
+        public ComponentNameSet(String colonSeparatedPackageNames) {
+            super(colonSeparatedPackageNames);
+        }
+
+        @Override
+        protected ComponentName itemFromString(String s) {
+            return ComponentName.unflattenFromString(s);
+        }
+
+        @Override
+        protected String itemToString(ComponentName item) {
+            return item.flattenToString();
+        }
+
+        public static String add(String delimitedElements, ComponentName element) {
+            final ComponentNameSet set = new ComponentNameSet(delimitedElements);
+            if (set.contains(element)) {
+                return delimitedElements;
+            }
+            set.add(element);
+            return set.toString();
+        }
+
+        public static String remove(String delimitedElements, ComponentName element) {
+            final ComponentNameSet set = new ComponentNameSet(delimitedElements);
+            if (!set.contains(element)) {
+                return delimitedElements;
+            }
+            set.remove(element);
+            return set.toString();
+        }
+
+        public static boolean contains(String delimitedElements, ComponentName element) {
+            return ColonDelimitedSet.OfStrings.contains(
+                    delimitedElements, element.flattenToString());
+        }
+    }
+
+    public static class SettingStringHelper {
+        private final ContentResolver mContentResolver;
+        private final String mSettingName;
+        private final int mUserId;
+
+        public SettingStringHelper(ContentResolver contentResolver, String name, int userId) {
+            mContentResolver = contentResolver;
+            mUserId = userId;
+            mSettingName = name;
+        }
+
+        public String read() {
+            return Settings.Secure.getStringForUser(
+                    mContentResolver, mSettingName, mUserId);
+        }
+
+        public boolean write(String value) {
+            return Settings.Secure.putStringForUser(
+                    mContentResolver, mSettingName, value, mUserId);
+        }
+
+        public boolean modify(Function<String, String> change) {
+            return write(change.apply(read()));
+        }
+    }
+}
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index bfaf23c..6da6a39 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -15,7 +15,10 @@
  */
 package android.service.autofill;
 
-import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import com.android.internal.os.HandlerCaller;
 import android.annotation.SdkConstant;
 import android.app.Activity;
 import android.app.Service;
@@ -24,21 +27,13 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
 import android.util.Log;
-import android.view.autofill.Dataset;
 import android.view.autofill.FillResponse;
 
-import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
 //TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
 //life-cycle (and how state could be maintained on server-side) is well documented.
 
@@ -48,12 +43,7 @@
  * <p>Apps providing auto-fill capabilities must extend this service.
  */
 public abstract class AutoFillService extends Service {
-
     private static final String TAG = "AutoFillService";
-    static final boolean DEBUG = true; // TODO(b/33197203): set to false once stable
-
-    // TODO(b/33197203): check for device's memory size instead of DEBUG?
-    static final boolean DEBUG_PENDING_CALLBACKS = DEBUG;
 
     /**
      * The {@link Intent} that must be declared as handled by the service.
@@ -77,87 +67,37 @@
      */
     public static final String SERVICE_META_DATA = "android.autofill";
 
-    // Internal bundle keys.
-    /** @hide */ public static final String KEY_CALLBACK = "callback";
-    /** @hide */ public static final String KEY_SAVABLE_IDS = "savable_ids";
-    /** @hide */ public static final String EXTRA_CRYPTO_OBJECT_ID = "crypto_object_id";
-
-    // Prefix for public bundle keys.
-    private static final String KEY_PREFIX = "android.service.autofill.extra.";
-
-    /**
-     * Key of the {@link Bundle} passed to methods such as
-     * {@link #onSaveRequest(AssistStructure, Bundle, SaveCallback)} containing the extras set by
-     * {@link android.view.autofill.FillResponse.Builder#setExtras(Bundle)}.
-     */
-    public static final String EXTRA_RESPONSE_EXTRAS = KEY_PREFIX + "RESPONSE_EXTRAS";
-
-    /**
-     * Key of the {@link Bundle} passed to methods such as
-     * {@link #onSaveRequest(AssistStructure, Bundle, SaveCallback)} containing the extras set by
-     * {@link android.view.autofill.Dataset.Builder#setExtras(Bundle)}.
-     */
-    public static final String EXTRA_DATASET_EXTRAS = KEY_PREFIX + "DATASET_EXTRAS";
-
-    /**
-     * Used to indicate the user selected an action that requires authentication.
-     */
-    public static final int FLAG_AUTHENTICATION_REQUESTED = 1 << 0;
-
-    /**
-     * Used to indicate the user authentication succeeded.
-     */
-    public static final int FLAG_AUTHENTICATION_SUCCESS = 1 << 1;
-
-    /**
-     * Used to indicate the user authentication failed.
-     */
-    public static final int FLAG_AUTHENTICATION_ERROR = 1 << 2;
-
-    /**
-     * Used when the service requested Fingerprint authentication but such option is not available.
-     */
-    public static final int FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE  = 1 << 3;
+    // Internal extras
+    /** @hide */
+    public static final String EXTRA_ACTIVITY_TOKEN =
+            "android.service.autofill.EXTRA_ACTIVITY_TOKEN";
 
     // Handler messages.
     private static final int MSG_CONNECT = 1;
     private static final int MSG_DISCONNECT = 2;
-    private static final int MSG_AUTO_FILL_ACTIVITY = 3;
-    private static final int MSG_AUTHENTICATE_FILL_RESPONSE = 4;
-    private static final int MSG_AUTHENTICATE_DATASET = 5;
-    private static final int MSG_SAVE = 6;
+    private static final int MSG_ON_FILL_REQUEST = 3;
+    private static final int MSG_ON_SAVE_REQUEST = 4;
 
     private final IAutoFillService mInterface = new IAutoFillService.Stub() {
-
         @Override
-        public void autoFill(AssistStructure structure, IAutoFillServerCallback callback) {
-            mHandlerCaller
-                    .obtainMessageOO(MSG_AUTO_FILL_ACTIVITY, structure, callback)
+        public void onFillRequest(AssistStructure structure, Bundle extras,
+                IFillCallback callback) {
+            ICancellationSignal transport = CancellationSignal.createTransport();
+            try {
+                callback.onCancellable(transport);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+            mHandlerCaller.obtainMessageOOOO(MSG_ON_FILL_REQUEST, structure,
+                    CancellationSignal.fromTransport(transport), extras, callback)
                     .sendToTarget();
         }
 
         @Override
-        public void save(AssistStructure structure, IAutoFillServerCallback callback,
-                Bundle extras) throws RemoteException {
-            mHandlerCaller
-                    .obtainMessageOOO(MSG_SAVE, structure, callback, extras)
-                    .sendToTarget();
-        }
-
-        @Override
-        public void authenticateFillResponse(Bundle extras, int flags) {
-            final Message msg = mHandlerCaller.obtainMessage(MSG_AUTHENTICATE_FILL_RESPONSE);
-            msg.arg1 = flags;
-            msg.obj = extras;
-            mHandlerCaller.sendMessage(msg);
-        }
-
-        @Override
-        public void authenticateDataset(Bundle extras, int flags) {
-            final Message msg = mHandlerCaller.obtainMessage(MSG_AUTHENTICATE_DATASET);
-            msg.arg1 = flags;
-            msg.obj = extras;
-            mHandlerCaller.sendMessage(msg);
+        public void onSaveRequest(AssistStructure structure, Bundle extras,
+                ISaveCallback callback) {
+            mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure,
+                    extras, callback).sendToTarget();
         }
 
         @Override
@@ -171,63 +111,41 @@
         }
     };
 
-    private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() {
-
-        @Override
-        public void executeMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_CONNECT: {
-                    onConnected();
-                    break;
-                } case MSG_AUTO_FILL_ACTIVITY: {
-                    final SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        final AssistStructure structure = (AssistStructure) args.arg1;
-                        final IAutoFillServerCallback callback =
-                                (IAutoFillServerCallback) args.arg2;
-                        handleAutoFill(structure, callback);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                } case MSG_SAVE: {
-                    final SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        final AssistStructure structure = (AssistStructure) args.arg1;
-                        final IAutoFillServerCallback callback =
-                                (IAutoFillServerCallback) args.arg2;
-                        final Bundle extras = (Bundle) args.arg3;
-                        handleSave(structure, callback, extras);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                } case MSG_AUTHENTICATE_FILL_RESPONSE: {
-                    final int flags = msg.arg1;
-                    final Bundle extras = (Bundle) msg.obj;
-                    onFillResponseAuthenticationRequest(extras, flags);
-                    break;
-                } case MSG_AUTHENTICATE_DATASET: {
-                    final int flags = msg.arg1;
-                    final Bundle extras = (Bundle) msg.obj;
-                    onDatasetAuthenticationRequest(extras, flags);
-                    break;
-                } case MSG_DISCONNECT: {
-                    onDisconnected();
-                    break;
-                } default: {
-                    Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
-                }
+    private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+        switch (msg.what) {
+            case MSG_CONNECT: {
+                onConnected();
+                break;
+            } case MSG_ON_FILL_REQUEST: {
+                final SomeArgs args = (SomeArgs) msg.obj;
+                final AssistStructure structure = (AssistStructure) args.arg1;
+                final CancellationSignal cancellation = (CancellationSignal) args.arg2;
+                final Bundle extras = (Bundle) args.arg3;
+                final IFillCallback callback = (IFillCallback) args.arg4;
+                final FillCallback fillCallback = new FillCallback(callback);
+                args.recycle();
+                onFillRequest(structure, extras, cancellation, fillCallback);
+                break;
+            } case MSG_ON_SAVE_REQUEST: {
+                final SomeArgs args = (SomeArgs) msg.obj;
+                final AssistStructure structure = (AssistStructure) args.arg1;
+                final Bundle extras = (Bundle) args.arg2;
+                final ISaveCallback callback = (ISaveCallback) args.arg3;
+                final SaveCallback saveCallback = new SaveCallback(callback);
+                args.recycle();
+                onSaveRequest(structure, extras, saveCallback);
+                break;
+            } case MSG_DISCONNECT: {
+                onDisconnected();
+                break;
+            } default: {
+                Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
             }
         }
     };
 
     private HandlerCaller mHandlerCaller;
 
-    // User for debugging purposes
-    private final List<CallbackHelper.Dumpable> mPendingCallbacks =
-            DEBUG_PENDING_CALLBACKS ? new ArrayList<>() : null;
-
     /**
      * {@inheritDoc}
      *
@@ -236,7 +154,6 @@
     @Override
     public void onCreate() {
         super.onCreate();
-
         mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
     }
 
@@ -255,7 +172,7 @@
      * <p>You should generally do initialization here rather than in {@link #onCreate}.
      */
     public void onConnected() {
-        if (DEBUG) Log.d(TAG, "onConnected()");
+        //TODO(b/33197203): is not called anymore, fix it!
     }
 
     /**
@@ -267,14 +184,18 @@
      * to notify the result of the request.
      *
      * @param structure {@link Activity}'s view structure.
-     * @param data bundle containing additional arguments set by the Android system (currently none)
-     * or data passed by the service on previous calls to fullfill other sections of this activity
-     * (see {@link FillResponse} Javadoc for examples of multiple-sections requests).
-     * @param cancellationSignal signal for observing cancel requests.
+     * @param data bundle containing data passed by the service on previous calls to fill.
+     *     This bundle allows your service to keep state between fill and save requests
+     *     as well as when filling different sections of the UI as the system will try to
+     *     aggressively unbind from the service to conserve resources. See {@link FillResponse}
+     *     Javadoc for examples of multiple-sections requests.
+     * @param cancellationSignal signal for observing cancellation requests. The system will use
+     *     this to notify you that the fill result is no longer needed and you should stop
+     *     handling this fill request in order to save resources.
      * @param callback object used to notify the result of the request.
      */
-    public abstract void onFillRequest(AssistStructure structure, Bundle data,
-            CancellationSignal cancellationSignal, FillCallback callback);
+    public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
+            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
 
     /**
      * Called when user requests service to save the fields of an {@link Activity}.
@@ -284,108 +205,15 @@
      * to notify the result of the request.
      *
      * @param structure {@link Activity}'s view structure.
-     * @param data bundle containing additional arguments set by the Android system (currently none)
-     * or data passed by the service in the {@link FillResponse} that originated this call.
+     * @param data bundle containing data passed by the service on previous calls to fill.
+     *     This bundle allows your service to keep state between fill and save requests
+     *     as well as when filling different sections of the UI as the system will try to
+     *     aggressively unbind from the service to conserve resources. See {@link FillResponse}
+     *     Javadoc for examples of multiple-sections requests.
      * @param callback object used to notify the result of the request.
      */
-    public abstract void onSaveRequest(AssistStructure structure, Bundle data,
-            SaveCallback callback);
-
-    /**
-     * Called as result of the user action for a {@link FillResponse} that required authentication.
-     *
-     * <p>When the {@link FillResponse} required authentication through
-     * {@link android.view.autofill.FillResponse.Builder#requiresCustomAuthentication(Bundle, int)},
-     * this call indicates the user is requesting the service to authenticate him/her (and
-     * {@code flags} contains {@link #FLAG_AUTHENTICATION_REQUESTED}), and {@code extras} contains
-     * the {@link Bundle} passed to that method.
-     *
-     * <p>When the {@link FillResponse} required authentication through
-     * {@link android.view.autofill.FillResponse.Builder#requiresFingerprintAuthentication(
-     * android.hardware.fingerprint.FingerprintManager.CryptoObject, Bundle, int)},
-     * {@code flags} this call contains the result of the fingerprint authentication (such as
-     * {@link #FLAG_AUTHENTICATION_SUCCESS}, {@link #FLAG_AUTHENTICATION_ERROR}, and
-     * {@link #FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE}) and {@code extras} contains the
-     * {@link Bundle} passed to that method.
-     */
-    public void onFillResponseAuthenticationRequest(@SuppressWarnings("unused") Bundle extras,
-            int flags) {
-        if (DEBUG) Log.d(TAG, "onFillResponseAuthenticationRequest(): flags=" + flags);
-    }
-
-    /**
-     * Called as result of the user action for a {@link Dataset} that required authentication.
-     *
-     * <p>When the {@link Dataset} required authentication through
-     * {@link android.view.autofill.Dataset.Builder#requiresCustomAuthentication(Bundle, int)}, this
-     * call indicates the user is requesting the service to authenticate him/her (and {@code flags}
-     * contains {@link #FLAG_AUTHENTICATION_REQUESTED}), and {@code extras} contains the
-     * {@link Bundle} passed to that method.
-     *
-     * <p>When the {@link Dataset} required authentication through
-     * {@link android.view.autofill.Dataset.Builder#requiresFingerprintAuthentication(
-     * android.hardware.fingerprint.FingerprintManager.CryptoObject, Bundle, int)},
-     * {@code flags} this call contains the result of the fingerprint authentication (such as
-     * {@link #FLAG_AUTHENTICATION_SUCCESS}, {@link #FLAG_AUTHENTICATION_ERROR}, and
-     * {@link #FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE}) and {@code extras} contains the
-     * {@link Bundle} passed to that method.
-     */
-    public void onDatasetAuthenticationRequest(@SuppressWarnings("unused") Bundle extras,
-            int flags) {
-        if (DEBUG) Log.d(TAG, "onDatasetAuthenticationRequest(): flags=" + flags);
-    }
-
-    @Override
-    @CallSuper
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mPendingCallbacks != null) {
-            pw.print("Number of pending callbacks: "); pw.println(mPendingCallbacks.size());
-            final String prefix = "  ";
-            for (int i = 0; i < mPendingCallbacks.size(); i++) {
-                final CallbackHelper.Dumpable cb = mPendingCallbacks.get(i);
-                pw.print('#'); pw.print(i + 1); pw.println(':');
-                cb.dump(prefix, pw);
-            }
-            pw.println();
-        } else {
-            pw.println("Dumping disabled");
-        }
-    }
-
-    private void handleAutoFill(AssistStructure structure, IAutoFillServerCallback callback) {
-        final FillCallback fillCallback = new FillCallback(callback);
-        if (DEBUG_PENDING_CALLBACKS) {
-            addPendingCallback(fillCallback);
-        }
-        // TODO(b/33197203): hook up the cancelationSignal
-        onFillRequest(structure, null, new CancellationSignal(), fillCallback);
-        return;
-    }
-
-    private void handleSave(AssistStructure structure, IAutoFillServerCallback callback,
-            Bundle extras) {
-        final SaveCallback saveCallback = new SaveCallback(callback);
-        if (DEBUG_PENDING_CALLBACKS) {
-            addPendingCallback(saveCallback);
-        }
-        onSaveRequest(structure, extras, saveCallback);
-    }
-
-    private void addPendingCallback(CallbackHelper.Dumpable callback) {
-        if (mPendingCallbacks == null) {
-            // Shouldn't happend since call is controlled by DEBUG_PENDING_CALLBACKS guard.
-            Log.wtf(TAG, "addPendingCallback(): mPendingCallbacks not set");
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG, "Adding pending callback: " + callback);
-
-        callback.setFinalizer(() -> {
-            if (DEBUG) Log.d(TAG, "Removing pending callback: " + callback);
-            mPendingCallbacks.remove(callback);
-        });
-        mPendingCallbacks.add(callback);
-    }
+    public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
+            @NonNull SaveCallback callback);
 
     /**
      * Called when the Android system disconnects from the service.
@@ -393,6 +221,6 @@
      * <p> At this point this service may no longer be an active {@link AutoFillService}.
      */
     public void onDisconnected() {
-        if (DEBUG) Log.d(TAG, "onDisconnected()");
+        //TODO(b/33197203): is not called anymore, fix it!
     }
 }
diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java
index fd957f1..985e32f 100644
--- a/core/java/android/service/autofill/AutoFillServiceInfo.java
+++ b/core/java/android/service/autofill/AutoFillServiceInfo.java
@@ -16,6 +16,7 @@
 package android.service.autofill;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppGlobals;
 import android.content.ComponentName;
@@ -25,7 +26,6 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.os.RemoteException;
-import android.util.AndroidException;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -40,13 +40,10 @@
 /**
  * {@link ServiceInfo} and meta-data about an {@link AutoFillService}.
  *
- * <p>Upon construction, if {@link #getParseError()} is {@code null}, then the service is configured
- * correctly. Otherwise, {@link #getParseError()} indicates the parsing error.
- *
  * @hide
  */
 public final class AutoFillServiceInfo {
-    static final String TAG = "AutoFillServiceInfo";
+    private static final String TAG = "AutoFillServiceInfo";
 
     private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
             throws PackageManager.NameNotFoundException {
@@ -63,10 +60,9 @@
         throw new PackageManager.NameNotFoundException(comp.toString());
     }
 
-    @Nullable
-    private final String mParseError;
-
+    @NonNull
     private final ServiceInfo mServiceInfo;
+
     @Nullable
     private final String mSettingsActivity;
 
@@ -77,17 +73,7 @@
 
     public AutoFillServiceInfo(PackageManager pm, ServiceInfo si) {
         mServiceInfo = si;
-        TypedArray metaDataArray;
-        try {
-            metaDataArray = getMetaDataArray(pm, si);
-        } catch (AndroidException e) {
-            mParseError = e.getMessage();
-            mSettingsActivity = null;
-            Log.w(TAG, mParseError, e);
-            return;
-        }
-
-        mParseError = null;
+        final TypedArray metaDataArray = getMetaDataArray(pm, si);
         if (metaDataArray != null) {
             mSettingsActivity =
                     metaDataArray.getString(R.styleable.AutoFillService_settingsActivity);
@@ -101,12 +87,11 @@
      * Gets the meta-data as a TypedArray, or null if not provided, or throws if invalid.
      */
     @Nullable
-    private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si)
-            throws AndroidException {
+    private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si) {
         // Check for permissions.
         if (!Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) {
-            throw new AndroidException(
-                "Service does not require permission " + Manifest.permission.BIND_AUTO_FILL);
+            Log.e(TAG, "Service does not require permission " + Manifest.permission.BIND_AUTO_FILL);
+            return null;
         }
 
         // Get the AutoFill metadata, if declared.
@@ -125,11 +110,13 @@
                         && type != XmlPullParser.START_TAG) {
                 }
             } catch (XmlPullParserException | IOException e) {
-                throw new AndroidException("Error parsing auto fill service meta-data: " + e, e);
+                Log.e(TAG, "Error parsing auto fill service meta-data", e);
+                return null;
             }
 
             if (!"autofill-service".equals(parser.getName())) {
-                throw new AndroidException("Meta-data does not start with autofill-service tag");
+                Log.e(TAG, "Meta-data does not start with autofill-service tag");
+                return null;
             }
             attrs = Xml.asAttributeSet(parser);
 
@@ -138,7 +125,8 @@
             try {
                 res = pm.getResourcesForApplication(si.applicationInfo);
             } catch (PackageManager.NameNotFoundException e) {
-                throw new AndroidException("Error getting application resources: " + e, e);
+                Log.e(TAG, "Error getting application resources", e);
+                return null;
             }
 
             return res.obtainAttributes(attrs, R.styleable.AutoFillService);
@@ -147,11 +135,6 @@
         }
     }
 
-    @Nullable
-    public String getParseError() {
-        return mParseError;
-    }
-
     public ServiceInfo getServiceInfo() {
         return mServiceInfo;
     }
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 7cab7ae..a306809 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -16,56 +16,32 @@
 
 package android.service.autofill;
 
-import static android.service.autofill.AutoFillService.DEBUG;
-import static android.util.DebugUtils.flagsToString;
-
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
-import android.service.autofill.CallbackHelper.Dumpable;
-import android.service.autofill.CallbackHelper.Finalizer;
-import android.util.Log;
-import android.view.autofill.Dataset;
 import android.view.autofill.FillResponse;
 
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.io.PrintWriter;
-
 /**
  * Handles auto-fill requests from the {@link AutoFillService} into the {@link Activity} being
  * auto-filled.
- *
- * <p>This class is thread safe.
  */
-public final class FillCallback implements Dumpable {
-
-    private static final String TAG = "FillCallback";
-
-    // NOTE: constants below are public so they can be used by flagsToString()
-    /** @hide */ public static final int STATE_INITIAL = 1 << 0;
-    /** @hide */ public static final int STATE_WAITING_FILL_RESPONSE_AUTH_RESPONSE = 1 << 1;
-    /** @hide */ public static final int STATE_WAITING_DATASET_AUTH_RESPONSE = 1 << 2;
-    /** @hide */ public static final int STATE_FINISHED_OK = 1 << 3;
-    /** @hide */ public static final int STATE_FINISHED_FAILURE = 1 << 4;
-    /** @hide */ public static final int STATE_FINISHED_ERROR = 1 << 5;
-    /** @hide */ public static final int STATE_FINISHED_AUTHENTICATED = 1 << 6;
-
-    private final IAutoFillServerCallback mCallback;
-
-    @GuardedBy("mCallback")
-    private int mState = STATE_INITIAL;
-
-    @GuardedBy("mCallback")
-    private Finalizer mFinalizer;
+public final class FillCallback implements Parcelable {
+    private final IFillCallback mCallback;
+    private boolean mCalled;
 
     /** @hide */
-    FillCallback(IAutoFillServerCallback callback) {
+    public FillCallback(IFillCallback callback) {
         mCallback = callback;
     }
 
+    /** @hide */
+    private FillCallback(Parcel parcel) {
+        mCallback = IFillCallback.Stub.asInterface(parcel.readStrongBinder());
+    }
+
     /**
      * Notifies the Android System that an
      * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle,
@@ -76,43 +52,12 @@
      * {@link FillResponse} for examples.
      */
     public void onSuccess(@Nullable FillResponse response) {
-        final boolean authRequired = response != null && response.isAuthRequired();
-
-        if (DEBUG) Log.d(TAG, "onSuccess(): authReq= " + authRequired + ", resp=" + response);
-
-        synchronized (mCallback) {
-            if (authRequired) {
-                assertOnStateLocked(STATE_INITIAL);
-            } else {
-                assertOnStateLocked(STATE_INITIAL | STATE_WAITING_FILL_RESPONSE_AUTH_RESPONSE
-                        | STATE_WAITING_DATASET_AUTH_RESPONSE);
-            }
-
-            try {
-                mCallback.showResponse(response);
-                if (authRequired) {
-                    mState = STATE_WAITING_FILL_RESPONSE_AUTH_RESPONSE;
-                } else {
-                    // Check if at least one dataset requires authentication.
-                    boolean waitingAuth = false;
-                    if (response != null) {
-                        for (Dataset dataset : response.getDatasets()) {
-                            if (dataset.isAuthRequired()) {
-                                waitingAuth = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (waitingAuth) {
-                        mState = STATE_WAITING_DATASET_AUTH_RESPONSE;
-                    } else {
-                        setFinalStateLocked(STATE_FINISHED_OK);
-                    }
-                }
-            } catch (RemoteException e) {
-                setFinalStateLocked(STATE_FINISHED_ERROR);
-                e.rethrowAsRuntimeException();
-            }
+        assertNotCalled();
+        mCalled = true;
+        try {
+            mCallback.onSuccess(response);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -124,118 +69,43 @@
      *
      * @param message error message to be displayed to the user.
      */
-    public void onFailure(CharSequence message) {
-        if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
-
-        Preconditions.checkArgument(message != null, "message cannot be null");
-
-        synchronized (mCallback) {
-            assertOnStateLocked(STATE_INITIAL | STATE_WAITING_FILL_RESPONSE_AUTH_RESPONSE
-                    | STATE_WAITING_DATASET_AUTH_RESPONSE);
-
-            try {
-                mCallback.showError(message);
-                setFinalStateLocked(STATE_FINISHED_FAILURE);
-            } catch (RemoteException e) {
-                setFinalStateLocked(STATE_FINISHED_ERROR);
-                e.rethrowAsRuntimeException();
-            }
+    public void onFailure(@Nullable CharSequence message) {
+        assertNotCalled();
+        mCalled = true;
+        try {
+            mCallback.onFailure(message);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
         }
     }
 
-    /**
-     * Notifies the Android System when the user authenticated a {@link FillResponse} previously
-     * passed to {@link #onSuccess(FillResponse)}.
-     *
-     * @param flags must contain either
-     * {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_ERROR} or
-     * {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_SUCCESS}.
-     */
-    public void onFillResponseAuthentication(int flags) {
-        if (DEBUG) Log.d(TAG, "onFillResponseAuthentication(): flags=" + flags);
-
-        synchronized (mCallback) {
-            assertOnStateLocked(STATE_WAITING_FILL_RESPONSE_AUTH_RESPONSE);
-
-            try {
-                mCallback.unlockFillResponse(flags);
-                setFinalStateLocked(STATE_FINISHED_AUTHENTICATED);
-            } catch (RemoteException e) {
-                setFinalStateLocked(STATE_FINISHED_ERROR);
-                e.rethrowAsRuntimeException();
-            }
-        }
-    }
-
-    /**
-     * Notifies the Android System when the user authenticated a {@link Dataset} previously passed
-     * to {@link #onSuccess(FillResponse)}.
-     *
-     * @param dataset values to fill the activity with in case of successful authentication of a
-     * previously locked (and empty) dataset).
-     * @param flags must contain either
-     * {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_ERROR} or
-     * {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_SUCCESS}.
-     */
-    public void onDatasetAuthentication(@Nullable Dataset dataset, int flags) {
-        if (DEBUG) Log.d(TAG, "onDatasetAuthentication(): dataset=" + dataset + ", flags=" + flags);
-
-        synchronized (mCallback) {
-            assertOnStateLocked(STATE_WAITING_DATASET_AUTH_RESPONSE);
-
-            try {
-                mCallback.unlockDataset(dataset, flags);
-                setFinalStateLocked(STATE_FINISHED_AUTHENTICATED);
-            } catch (RemoteException e) {
-                setFinalStateLocked(STATE_FINISHED_ERROR);
-                e.rethrowAsRuntimeException();
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        if (!DEBUG) return super.toString();
-
-        return "FillCallback: [mState = " + mState + "]";
-    }
-
     /** @hide */
     @Override
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("FillCallback: mState="); pw.println(mState);
+    public int describeContents() {
+        return 0;
     }
 
     /** @hide */
     @Override
-    public void setFinalizer(Finalizer f) {
-        synchronized (mCallback) {
-            mFinalizer = f;
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeStrongBinder(mCallback.asBinder());
+    }
+
+    private void assertNotCalled() {
+        if (mCalled) {
+            throw new IllegalStateException("Already called");
         }
     }
 
-    /**
-     * Sets a final state (where the callback cannot be used anymore) and notifies the
-     * {@link Finalizer} (if any).
-     */
-    private void setFinalStateLocked(int state) {
-        if (DEBUG) Log.d(TAG, "setFinalState(): " + state);
-        mState = state;
-
-        if (mFinalizer != null) {
-            mFinalizer.gone();
+    public static final Creator<FillCallback> CREATOR = new Creator<FillCallback>() {
+        @Override
+        public FillCallback createFromParcel(Parcel parcel) {
+            return new FillCallback(parcel);
         }
-    }
 
-    // TODO(b/33197203): move and/or re-add state check logic on server side to avoid malicious app
-    // calling the callback on wrong state.
-
-    // Make sure callback method is called during the proper lifecycle state.
-    private void assertOnStateLocked(int flags) {
-        if (DEBUG) Log.d(TAG, "assertOnState(): current=" + mState + ", required=" + flags);
-
-        Preconditions.checkState((flags & mState) != 0,
-                "invalid state: required " + flagsToString(FillCallback.class, "STATE_", flags)
-                + ", current is " + flagsToString(FillCallback.class, "STATE_", mState));
-    }
+        @Override
+        public FillCallback[] newArray(int size) {
+            return new FillCallback[size];
+        }
+    };
 }
diff --git a/core/java/android/service/autofill/IAutoFillAppCallback.aidl b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
index 8c3898a..c2e72e8 100644
--- a/core/java/android/service/autofill/IAutoFillAppCallback.aidl
+++ b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
@@ -18,6 +18,8 @@
 
 import java.util.List;
 
+import android.content.Intent;
+import android.content.IntentSender;
 import android.view.autofill.Dataset;
 
 /**
@@ -31,4 +33,15 @@
       * Auto-fills the activity with the contents of a dataset.
       */
     void autoFill(in Dataset dataset);
+
+    /**
+      * Start an intent sender from the context of the filled app
+      */
+    void startIntentSender(in IntentSender intent, in Intent fillInIntent);
+
+    /**
+      * Called by system_service to enable auto-fill in a session, after it was asynchronously
+      * started by the manager.
+      */
+    void enableSession();
 }
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index 088e649..b39c0c8 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -18,6 +18,7 @@
 
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.view.autofill.AutoFillId;
 import android.view.autofill.AutoFillValue;
 
@@ -27,16 +28,13 @@
  * {@hide}
  */
 oneway interface IAutoFillManagerService {
+    // Methods called by AutoFillManager
+    void startSession(in IBinder activityToken, in IBinder appCallback, in AutoFillId autoFillId,
+                      in Rect bounds, in AutoFillValue value);
+    void updateSession(in IBinder activityToken, in AutoFillId id, in Rect bounds,
+                       in AutoFillValue value, int flags);
+    void finishSession(in IBinder activityToken);
 
-    // Called by AutoFillManager (app).
-    void requestAutoFill(in AutoFillId id, in Rect bounds, int flags);
-
-    // Called by AutoFillManager (app).
-    void onValueChanged(in AutoFillId id, in AutoFillValue value);
-
-    // Called by ShellCommand only.
-    void requestAutoFillForUser(int userId);
-
-    // Called by ShellCommand only.
+    // Methods called by ShellCommand
     void requestSaveForUser(int userId);
 }
diff --git a/core/java/android/service/autofill/IAutoFillServerCallback.aidl b/core/java/android/service/autofill/IAutoFillServerCallback.aidl
deleted file mode 100644
index 480438a..0000000
--- a/core/java/android/service/autofill/IAutoFillServerCallback.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.autofill;
-
-import java.util.List;
-
-import android.os.Bundle;
-import android.view.autofill.AutoFillId;
-import android.view.autofill.Dataset;
-import android.view.autofill.FillResponse;
-
-/**
- * Object running in the AutoFillService process and used to communicate back with system_server.
- *
- * @hide
- */
-// TODO(b/33197203): rename to IAutoFillServerSession
-oneway interface IAutoFillServerCallback {
-    // TODO(b/33197203): document methods
-    void showResponse(in FillResponse response);
-    void showError(CharSequence message);
-    void onSaved();
-    void unlockFillResponse(int flags);
-    void unlockDataset(in Dataset dataset, int flags);
-}
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index a4e6ebc..fa1ea65 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -18,19 +18,20 @@
 
 import android.app.assist.AssistStructure;
 import android.os.Bundle;
-import android.service.autofill.IAutoFillServerCallback;
+import android.service.autofill.IFillCallback;
+import android.service.autofill.ISaveCallback;
 import com.android.internal.os.IResultReceiver;
 
 /**
+ * Interface from the system to an auto fill service.
+ *
  * @hide
  */
-// TODO(b/33197203): document class and methods
 oneway interface IAutoFillService {
-    // TODO(b/33197203): rename method to make them more consistent
-    void autoFill(in AssistStructure structure, in IAutoFillServerCallback callback);
-    void save(in AssistStructure structure, in IAutoFillServerCallback callback, in Bundle extras);
-    void authenticateFillResponse(in Bundle extras, int flags);
-    void authenticateDataset(in Bundle extras, int flags);
+    void onFillRequest(in AssistStructure structure, in Bundle extras,
+            in IFillCallback callback);
+    void onSaveRequest(in AssistStructure structure, in Bundle extras,
+            in ISaveCallback callback);
     void onConnected();
     void onDisconnected();
 }
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/android/service/autofill/IFillCallback.aidl
similarity index 66%
copy from core/java/android/service/autofill/CallbackHelper.java
copy to core/java/android/service/autofill/IFillCallback.aidl
index ded8f97..537403e 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/android/service/autofill/IFillCallback.aidl
@@ -13,18 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.service.autofill;
 
-import java.io.PrintWriter;
+import android.os.ICancellationSignal;
 
-final class CallbackHelper {
+import android.view.autofill.FillResponse;
 
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
-
-    static interface Finalizer {
-        void gone();
-    }
+/**
+ * Interface to receive the result of a save request.
+ *
+ * @hide
+ */
+interface IFillCallback {
+    void onCancellable(in ICancellationSignal cancellation);
+    void onSuccess(in FillResponse response);
+    void onFailure(CharSequence message);
 }
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/android/service/autofill/ISaveCallback.aidl
similarity index 72%
rename from core/java/android/service/autofill/CallbackHelper.java
rename to core/java/android/service/autofill/ISaveCallback.aidl
index ded8f97..e260c73 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/android/service/autofill/ISaveCallback.aidl
@@ -13,18 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.service.autofill;
 
-import java.io.PrintWriter;
-
-final class CallbackHelper {
-
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
-
-    static interface Finalizer {
-        void gone();
-    }
+/**
+ * Interface to receive the result of a save request.
+ *
+ * @hide
+ */
+interface ISaveCallback {
+    void onSuccess();
+    void onFailure(CharSequence message);
 }
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 9dd9795..46b3072 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -16,21 +16,9 @@
 
 package android.service.autofill;
 
-import static android.service.autofill.AutoFillService.DEBUG;
-
 import android.app.Activity;
-import android.app.assist.AssistStructure.ViewNode;
 import android.os.Bundle;
 import android.os.RemoteException;
-import android.service.autofill.CallbackHelper.Dumpable;
-import android.service.autofill.CallbackHelper.Finalizer;
-import android.util.Log;
-import android.view.autofill.AutoFillId;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.io.PrintWriter;
 
 /**
  * Handles save requests from the {@link AutoFillService} into the {@link Activity} being
@@ -38,20 +26,12 @@
  *
  * <p>This class is thread safe.
  */
-public final class SaveCallback implements Dumpable {
-
-    private static final String TAG = "SaveCallback";
-
-    private final IAutoFillServerCallback mCallback;
-
-    @GuardedBy("mCallback")
-    private boolean mReplied = false;
-
-    @GuardedBy("mCallback")
-    private Finalizer mFinalizer;
+public final class SaveCallback {
+    private final ISaveCallback mCallback;
+    private boolean mCalled;
 
     /** @hide */
-    SaveCallback(IAutoFillServerCallback callback) {
+    SaveCallback(ISaveCallback callback) {
         mCallback = callback;
     }
 
@@ -63,17 +43,12 @@
      * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onSuccess() {
-        if (DEBUG) Log.d(TAG, "onSuccess()");
-
-        synchronized (mCallback) {
-            checkNotRepliedYetLocked();
-            try {
-                mCallback.onSaved();
-            } catch (RemoteException e) {
-                e.rethrowAsRuntimeException();
-            } finally {
-                setRepliedLocked();
-            }
+        assertNotCalled();
+        mCalled = true;
+        try {
+            mCallback.onSuccess();
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -87,54 +62,18 @@
      * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onFailure(CharSequence message) {
-        if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
-
-        synchronized (mCallback) {
-            checkNotRepliedYetLocked();
-
-            try {
-                mCallback.showError(message);
-            } catch (RemoteException e) {
-                e.rethrowAsRuntimeException();
-            } finally {
-                setRepliedLocked();
-            }
+        assertNotCalled();
+        mCalled = true;
+        try {
+            mCallback.onFailure(message);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
         }
     }
 
-    /** @hide */
-    @Override
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("SaveCallback: mReplied="); pw.println(mReplied);
-    }
-
-    /** @hide */
-    @Override
-    public void setFinalizer(Finalizer f) {
-        synchronized (mCallback) {
-            mFinalizer = f;
-        }
-    }
-
-    @Override
-    public String toString() {
-        if (!DEBUG) return super.toString();
-
-        return "SaveCallback: [mReplied= " + mReplied + "]";
-    }
-
-    // There can be only one!!
-    private void checkNotRepliedYetLocked() {
-        Preconditions.checkState(!mReplied, "already replied");
-    }
-
-    private void setRepliedLocked() {
-        if (DEBUG) Log.d(TAG, "setReplied()");
-
-        mReplied = true;
-
-        if (mFinalizer != null) {
-            mFinalizer.gone();
+    private void assertNotCalled() {
+        if (mCalled) {
+            throw new IllegalStateException("Already called");
         }
     }
 }
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 887f4b6..1781c2a 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -130,6 +130,11 @@
      */
     public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
 
+    /**
+     * @hide
+     */
+    public static final String EXTRA_STATE = "state";
+
     private final H mHandler = new H(Looper.getMainLooper());
 
     private boolean mListening = false;
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 120a37a..bd1b44c 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -17,6 +17,7 @@
 package android.service.textservice;
 
 import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerServiceCallback;
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 
@@ -311,16 +312,39 @@
             mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
         }
 
+        /**
+         * Called from the system when an application is requesting a new spell checker session.
+         *
+         * <p>Note: This is an internal protocol used by the system to establish spell checker
+         * sessions, which is not guaranteed to be stable and is subject to change.</p>
+         *
+         * @param locale locale to be returned from {@link Session#getLocale()}
+         * @param listener IPC channel object to be used to implement
+         *                 {@link Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)} and
+         *                 {@link Session#onGetSuggestions(TextInfo, int)}
+         * @param bundle bundle to be returned from {@link Session#getBundle()}
+         * @param callback IPC channel to return the result to the caller in an asynchronous manner
+         */
         @Override
-        public ISpellCheckerSession getISpellCheckerSession(
-                String locale, ISpellCheckerSessionListener listener, Bundle bundle) {
+        public void getISpellCheckerSession(
+                String locale, ISpellCheckerSessionListener listener, Bundle bundle,
+                ISpellCheckerServiceCallback callback) {
             final SpellCheckerService service = mInternalServiceRef.get();
-            if (service == null) return null;
-            final Session session = service.createSession();
-            final InternalISpellCheckerSession internalSession =
-                    new InternalISpellCheckerSession(locale, listener, bundle, session);
-            session.onCreate();
-            return internalSession;
+            final InternalISpellCheckerSession internalSession;
+            if (service == null) {
+                // If the owner SpellCheckerService object was already destroyed and got GC-ed,
+                // the weak-reference returns null and we should just ignore this request.
+                internalSession = null;
+            } else {
+                final Session session = service.createSession();
+                internalSession =
+                        new InternalISpellCheckerSession(locale, listener, bundle, session);
+                session.onCreate();
+            }
+            try {
+                callback.onSessionCreated(internalSession);
+            } catch (RemoteException e) {
+            }
         }
     }
 
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e9bbc2d..ca736e3 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -135,6 +135,7 @@
     FrameLayout mContentFrame;
     SoftInputWindow mWindow;
 
+    boolean mUiEnabled = true;
     boolean mInitialized;
     boolean mWindowAdded;
     boolean mWindowVisible;
@@ -1001,35 +1002,40 @@
 
         try {
             mInShowWindow = true;
+            onPrepareShow(args, flags);
             if (!mWindowVisible) {
-                if (!mWindowAdded) {
-                    mWindowAdded = true;
-                    View v = onCreateContentView();
-                    if (v != null) {
-                        setContentView(v);
-                    }
-                }
+                ensureWindowAdded();
             }
             onShow(args, flags);
             if (!mWindowVisible) {
                 mWindowVisible = true;
-                mWindow.show();
+                if (mUiEnabled) {
+                    mWindow.show();
+                }
             }
             if (showCallback != null) {
-                mRootView.invalidate();
-                mRootView.getViewTreeObserver().addOnPreDrawListener(
-                        new ViewTreeObserver.OnPreDrawListener() {
-                            @Override
-                            public boolean onPreDraw() {
-                                mRootView.getViewTreeObserver().removeOnPreDrawListener(this);
-                                try {
-                                    showCallback.onShown();
-                                } catch (RemoteException e) {
-                                    Log.w(TAG, "Error calling onShown", e);
+                if (mUiEnabled) {
+                    mRootView.invalidate();
+                    mRootView.getViewTreeObserver().addOnPreDrawListener(
+                            new ViewTreeObserver.OnPreDrawListener() {
+                                @Override
+                                public boolean onPreDraw() {
+                                    mRootView.getViewTreeObserver().removeOnPreDrawListener(this);
+                                    try {
+                                        showCallback.onShown();
+                                    } catch (RemoteException e) {
+                                        Log.w(TAG, "Error calling onShown", e);
+                                    }
+                                    return true;
                                 }
-                                return true;
-                            }
-                        });
+                            });
+                } else {
+                    try {
+                        showCallback.onShown();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Error calling onShown", e);
+                    }
+                }
             }
         } finally {
             mWindowWasVisible = true;
@@ -1039,7 +1045,7 @@
 
     void doHide() {
         if (mWindowVisible) {
-            mWindow.hide();
+            ensureWindowHidden();
             mWindowVisible = false;
             onHide();
         }
@@ -1058,19 +1064,56 @@
         }
     }
 
-    void initViews() {
+    void ensureWindowCreated() {
+        if (mInitialized) {
+            return;
+        }
+
+        if (!mUiEnabled) {
+            throw new IllegalStateException("setUiEnabled is false");
+        }
+
         mInitialized = true;
+        mInflater = (LayoutInflater)mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
+                mCallbacks, this, mDispatcherState,
+                WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
+        mWindow.getWindow().addFlags(
+                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
+                        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+                        WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
 
         mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
         mRootView = mInflater.inflate(
                 com.android.internal.R.layout.voice_interaction_session, null);
         mRootView.setSystemUiVisibility(
                 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
         mWindow.setContentView(mRootView);
         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
 
         mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
+
+        mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
+        mWindow.setToken(mToken);
+    }
+
+    void ensureWindowAdded() {
+        if (mUiEnabled && !mWindowAdded) {
+            mWindowAdded = true;
+            ensureWindowCreated();
+            View v = onCreateContentView();
+            if (v != null) {
+                setContentView(v);
+            }
+        }
+    }
+
+    void ensureWindowHidden() {
+        if (mWindow != null) {
+            mWindow.hide();
+        }
     }
 
     /**
@@ -1151,6 +1194,24 @@
     }
 
     /**
+     * Control whether the UI layer for this session is enabled.  It is enabled by default.
+     * If set to false, you will not be able to provide a UI through {@link #onCreateContentView()}.
+     */
+    public void setUiEnabled(boolean enabled) {
+        if (mUiEnabled != enabled) {
+            mUiEnabled = enabled;
+            if (mWindowVisible) {
+                if (enabled) {
+                    ensureWindowAdded();
+                    mWindow.show();
+                } else {
+                    ensureWindowHidden();
+                }
+            }
+        }
+    }
+
+    /**
      * You can call this to customize the theme used by your IME's window.
      * This must be set before {@link #onCreate}, so you
      * will typically call it in your constructor with the resource ID
@@ -1242,6 +1303,7 @@
      * Convenience for inflating views.
      */
     public LayoutInflater getLayoutInflater() {
+        ensureWindowCreated();
         return mInflater;
     }
 
@@ -1249,6 +1311,7 @@
      * Retrieve the window being used to show the session's UI.
      */
     public Dialog getWindow() {
+        ensureWindowCreated();
         return mWindow;
     }
 
@@ -1278,18 +1341,17 @@
     private void doOnCreate() {
         mTheme = mTheme != 0 ? mTheme
                 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
-        mInflater = (LayoutInflater)mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
-                mCallbacks, this, mDispatcherState,
-                WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
-        mWindow.getWindow().addFlags(
-                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
-                WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
-        initViews();
-        mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
-        mWindow.setToken(mToken);
+    }
+
+    /**
+     * Called prior to {@link #onShow} before any UI setup has occurred.  Not generally useful.
+     *
+     * @param args The arguments that were supplied to
+     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
+     * @param showFlags The show flags originally provided to
+     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
+     */
+    public void onPrepareShow(Bundle args, int showFlags) {
     }
 
     /**
@@ -1327,6 +1389,7 @@
     }
 
     public void setContentView(View view) {
+        ensureWindowCreated();
         mContentFrame.removeAllViews();
         mContentFrame.addView(view, new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
@@ -1623,7 +1686,8 @@
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         writer.print(prefix); writer.print("mToken="); writer.println(mToken);
         writer.print(prefix); writer.print("mTheme=#"); writer.println(Integer.toHexString(mTheme));
-        writer.print(prefix); writer.print("mInitialized="); writer.println(mInitialized);
+        writer.print(prefix); writer.print("mUiEnabled="); writer.println(mUiEnabled);
+        writer.print(" mInitialized="); writer.println(mInitialized);
         writer.print(prefix); writer.print("mWindowAdded="); writer.print(mWindowAdded);
         writer.print(" mWindowVisible="); writer.println(mWindowVisible);
         writer.print(prefix); writer.print("mWindowWasVisible="); writer.print(mWindowWasVisible);
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 62ecab3..10e4177 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -42,5 +42,13 @@
      */
     boolean getVrModeState();
 
+    /**
+     * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
+     * remain in VR mode even if the foreground does not specify VR mode being enabled. Mainly used
+     * by VR viewers to indicate that a device is placed in a VR viewer.
+     *
+     * @param enabled true if the device should be placed in persistent VR mode.
+     */
+    void setPersistentVrModeEnabled(in boolean enabled);
 }
 
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 80d3c8a..08df64f 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -409,6 +409,10 @@
         return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_RATE, Engine.DEFAULT_RATE);
     }
 
+    private int getDefaultPitch() {
+        return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_PITCH, Engine.DEFAULT_PITCH);
+    }
+
     private String[] getSettingsLocale() {
         final Locale locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
         return TtsEngines.toOldLocaleStringFormat(locale);
@@ -936,7 +940,7 @@
         }
 
         int getPitch() {
-            return getIntParam(mParams, Engine.KEY_PARAM_PITCH, Engine.DEFAULT_PITCH);
+            return getIntParam(mParams, Engine.KEY_PARAM_PITCH, getDefaultPitch());
         }
 
         @Override
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index bb952ab..ac9c0d7 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -62,6 +62,7 @@
 
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
 
 import java.lang.reflect.Array;
 import java.util.Iterator;
@@ -455,10 +456,7 @@
      * @return true if str is null or zero length
      */
     public static boolean isEmpty(@Nullable CharSequence str) {
-        if (str == null || str.length() == 0)
-            return true;
-        else
-            return false;
+        return str == null || str.length() == 0;
     }
 
     /** {@hide} */
@@ -466,6 +464,16 @@
         return isEmpty(str) ? null : str;
     }
 
+    /** {@hide} */
+    public static String emptyIfNull(@Nullable String str) {
+        return str == null ? "" : str;
+    }
+
+    /** {@hide} */
+    public static String firstNotEmpty(@Nullable String a, @NonNull String b) {
+        return !isEmpty(a) ? a : Preconditions.checkStringNotEmpty(b);
+    }
+
     /**
      * Returns the length that the specified CharSequence would have if
      * spaces and ASCII control characters were trimmed from the start and end,
diff --git a/core/java/android/text/style/ClickableSpan.java b/core/java/android/text/style/ClickableSpan.java
index a183427..b098f16 100644
--- a/core/java/android/text/style/ClickableSpan.java
+++ b/core/java/android/text/style/ClickableSpan.java
@@ -22,7 +22,7 @@
 /**
  * If an object of this type is attached to the text of a TextView
  * with a movement method of LinkMovementMethod, the affected spans of
- * text can be selected.  If clicked, the {@link #onClick} method will
+ * text can be selected. If selected and clicked, the {@link #onClick} method will
  * be called.
  */
 public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index 4b0b065..5303855 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -141,9 +141,10 @@
      * child view will be relative to its parent's final position, so it may appear to "jump"
      * at the beginning.</p>
      *
-     * @return <code>true</code> when a changed parent should execute the transition
-     * inside the scene root's overlay or <code>false</code> if a parent change only
-     * affects the transform of the transitioning view.
+     * @param reparentWithOverlay <code>true</code> when a changed parent should execute the
+     *                            transition inside the scene root's overlay or <code>false</code>
+     *                            if a parent change only affects the transform of the transitioning
+     *                            view.
      * @attr ref android.R.styleable#ChangeTransform_reparentWithOverlay
      */
     public void setReparentWithOverlay(boolean reparentWithOverlay) {
@@ -465,7 +466,7 @@
         }
     }
 
-    private static class GhostListener extends Transition.TransitionListenerAdapter {
+    private static class GhostListener extends TransitionListenerAdapter {
         private View mView;
         private View mStartView;
         private GhostView mGhostView;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 8823605..af2547e 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -2342,34 +2342,6 @@
     }
 
     /**
-     * Utility adapter class to avoid having to override all three methods
-     * whenever someone just wants to listen for a single event.
-     *
-     * @hide
-     * */
-    public static class TransitionListenerAdapter implements TransitionListener {
-        @Override
-        public void onTransitionStart(Transition transition) {
-        }
-
-        @Override
-        public void onTransitionEnd(Transition transition) {
-        }
-
-        @Override
-        public void onTransitionCancel(Transition transition) {
-        }
-
-        @Override
-        public void onTransitionPause(Transition transition) {
-        }
-
-        @Override
-        public void onTransitionResume(Transition transition) {
-        }
-    }
-
-    /**
      * Holds information about each animator used when a new transition starts
      * while other transitions are still running to determine whether a running
      * animation should be canceled or a new animation noop'd. The structure holds
diff --git a/core/java/android/transition/TransitionListenerAdapter.java b/core/java/android/transition/TransitionListenerAdapter.java
new file mode 100644
index 0000000..c217949
--- /dev/null
+++ b/core/java/android/transition/TransitionListenerAdapter.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.transition;
+
+/**
+ * This adapter class provides empty implementations of the methods from {@link
+ * android.transition.Transition.TransitionListener}.
+ * Any custom listener that cares only about a subset of the methods of this listener can
+ * simply subclass this adapter class instead of implementing the interface directly.
+ */
+public abstract class TransitionListenerAdapter implements Transition.TransitionListener {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onTransitionStart(Transition transition) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onTransitionEnd(Transition transition) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onTransitionCancel(Transition transition) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onTransitionPause(Transition transition) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onTransitionResume(Transition transition) {
+    }
+}
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 6e4d78d..325ff38 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -298,7 +298,7 @@
                 previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
             }
             currentTransitions.add(mTransition);
-            mTransition.addListener(new Transition.TransitionListenerAdapter() {
+            mTransition.addListener(new TransitionListenerAdapter() {
                 @Override
                 public void onTransitionEnd(Transition transition) {
                     ArrayList<Transition> currentTransitions =
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 13ee48e..77e9f0f 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -17,9 +17,11 @@
 package android.view;
 
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN;
+import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.Binder;
 import android.os.Bundle;
@@ -29,7 +31,6 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
-import android.text.TextUtils;
 import android.text.style.AccessibilityClickableSpan;
 import android.text.style.ClickableSpan;
 import android.util.LongSparseArray;
@@ -41,7 +42,6 @@
 
 import com.android.internal.R;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -50,6 +50,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
+import java.util.function.Predicate;
 
 /**
  * Class for managing accessibility interactions initiated from the system
@@ -93,6 +94,19 @@
         mPrefetcher = new AccessibilityNodePrefetcher();
     }
 
+    private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid) {
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
     private boolean isShown(View view) {
         // The first two checks are made also made by isShown() which
         // however traverses the tree up to the parent to catch that.
@@ -106,7 +120,7 @@
     public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
             long accessibilityNodeId, Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-            long interrogatingTid, MagnificationSpec spec) {
+            long interrogatingTid, MagnificationSpec spec, Bundle arguments) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID;
         message.arg1 = flags;
@@ -118,18 +132,10 @@
         args.arg1 = callback;
         args.arg2 = spec;
         args.arg3 = interactiveRegion;
+        args.arg4 = arguments;
         message.obj = args;
 
-        // If the interrogation is performed by the same thread as the main UI
-        // thread in this process, set the message as a static reference so
-        // after this call completes the same thread but in the interrogating
-        // client can handle the message to generate the result.
-        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
-            AccessibilityInteractionClient.getInstanceForThread(
-                    interrogatingTid).setSameThreadMessage(message);
-        } else {
-            mHandler.sendMessage(message);
-        }
+        scheduleMessage(message, interrogatingPid, interrogatingTid);
     }
 
     private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
@@ -143,6 +149,7 @@
             (IAccessibilityInteractionConnectionCallback) args.arg1;
         final MagnificationSpec spec = (MagnificationSpec) args.arg2;
         final Region interactiveRegion = (Region) args.arg3;
+        final Bundle arguments = (Bundle) args.arg4;
 
         args.recycle();
 
@@ -160,29 +167,12 @@
                 root = findViewByAccessibilityId(accessibilityViewId);
             }
             if (root != null && isShown(root)) {
-                mPrefetcher.prefetchAccessibilityNodeInfos(root, virtualDescendantId, flags, infos);
+                mPrefetcher.prefetchAccessibilityNodeInfos(
+                        root, virtualDescendantId, flags, infos, arguments);
             }
         } finally {
-            try {
-                mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-                applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
-                // Recycle if called from another process. Specs are cached in the
-                // system process and obtained from a pool when read from parcel.
-                if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
-                    spec.recycle();
-                }
-                adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
-                callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
-                infos.clear();
-            } catch (RemoteException re) {
-                /* ignore - the other side will time out */
-            }
-
-            // Recycle if called from the same process. Regions are obtained in
-            // the system process and instantiated  when read from parcel.
-            if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
-                interactiveRegion.recycle();
-            }
+            updateInfosForViewportAndReturnFindNodeResult(
+                    infos, callback, interactionId, spec, interactiveRegion);
         }
     }
 
@@ -201,19 +191,9 @@
         args.arg2 = spec;
         args.arg3 = viewId;
         args.arg4 = interactiveRegion;
-
         message.obj = args;
 
-        // If the interrogation is performed by the same thread as the main UI
-        // thread in this process, set the message as a static reference so
-        // after this call completes the same thread but in the interrogating
-        // client can handle the message to generate the result.
-        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
-            AccessibilityInteractionClient.getInstanceForThread(
-                    interrogatingTid).setSameThreadMessage(message);
-        } else {
-            mHandler.sendMessage(message);
-        }
+        scheduleMessage(message, interrogatingPid, interrogatingTid);
     }
 
     private void findAccessibilityNodeInfosByViewIdUiThread(Message message) {
@@ -227,7 +207,6 @@
         final MagnificationSpec spec = (MagnificationSpec) args.arg2;
         final String viewId = (String) args.arg3;
         final Region interactiveRegion = (Region) args.arg4;
-
         args.recycle();
 
         final List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
@@ -257,25 +236,8 @@
                 mAddNodeInfosForViewId.reset();
             }
         } finally {
-            try {
-                mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-                applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
-                // Recycle if called from another process. Specs are cached in the
-                // system process and obtained from a pool when read from parcel.
-                if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
-                    spec.recycle();
-                }
-                adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
-                callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
-            } catch (RemoteException re) {
-                /* ignore - the other side will time out */
-            }
-
-            // Recycle if called from the same process. Regions are obtained in
-            // the system process and instantiated  when read from parcel.
-            if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
-                interactiveRegion.recycle();
-            }
+            updateInfosForViewportAndReturnFindNodeResult(
+                    infos, callback, interactionId, spec, interactiveRegion);
         }
     }
 
@@ -297,16 +259,7 @@
         args.arg4 = interactiveRegion;
         message.obj = args;
 
-        // If the interrogation is performed by the same thread as the main UI
-        // thread in this process, set the message as a static reference so
-        // after this call completes the same thread but in the interrogating
-        // client can handle the message to generate the result.
-        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
-            AccessibilityInteractionClient.getInstanceForThread(
-                    interrogatingTid).setSameThreadMessage(message);
-        } else {
-            mHandler.sendMessage(message);
-        }
+        scheduleMessage(message, interrogatingPid, interrogatingTid);
     }
 
     private void findAccessibilityNodeInfosByTextUiThread(Message message) {
@@ -375,31 +328,14 @@
                 }
             }
         } finally {
-            try {
-                mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-                applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
-                // Recycle if called from another process. Specs are cached in the
-                // system process and obtained from a pool when read from parcel.
-                if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
-                    spec.recycle();
-                }
-                adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
-                callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
-            } catch (RemoteException re) {
-                /* ignore - the other side will time out */
-            }
-
-            // Recycle if called from the same process. Regions are obtained in
-            // the system process and instantiated  when read from parcel.
-            if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
-                interactiveRegion.recycle();
-            }
+            updateInfosForViewportAndReturnFindNodeResult(
+                    infos, callback, interactionId, spec, interactiveRegion);
         }
     }
 
     public void findFocusClientThread(long accessibilityNodeId, int focusType,
             Region interactiveRegion, int interactionId,
-            IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
+            IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
             long interrogatingTid, MagnificationSpec spec) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FIND_FOCUS;
@@ -416,16 +352,7 @@
 
         message.obj = args;
 
-        // If the interrogation is performed by the same thread as the main UI
-        // thread in this process, set the message as a static reference so
-        // after this call completes the same thread but in the interrogating
-        // client can handle the message to generate the result.
-        if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
-            AccessibilityInteractionClient.getInstanceForThread(
-                    interrogatingTid).setSameThreadMessage(message);
-        } else {
-            mHandler.sendMessage(message);
-        }
+        scheduleMessage(message, interrogatingPid, interrogatingTid);
     }
 
     private void findFocusUiThread(Message message) {
@@ -497,31 +424,14 @@
                 }
             }
         } finally {
-            try {
-                mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-                applyAppScaleAndMagnificationSpecIfNeeded(focused, spec);
-                // Recycle if called from another process. Specs are cached in the
-                // system process and obtained from a pool when read from parcel.
-                if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
-                    spec.recycle();
-                }
-                adjustIsVisibleToUserIfNeeded(focused, interactiveRegion);
-                callback.setFindAccessibilityNodeInfoResult(focused, interactionId);
-            } catch (RemoteException re) {
-                /* ignore - the other side will time out */
-            }
-
-            // Recycle if called from the same process. Regions are obtained in
-            // the system process and instantiated  when read from parcel.
-            if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
-                interactiveRegion.recycle();
-            }
+            updateInfoForViewportAndReturnFindNodeResult(
+                    focused, callback, interactionId, spec, interactiveRegion);
         }
     }
 
     public void focusSearchClientThread(long accessibilityNodeId, int direction,
             Region interactiveRegion, int interactionId,
-            IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
+            IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
             long interrogatingTid, MagnificationSpec spec) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FOCUS_SEARCH;
@@ -537,16 +447,7 @@
 
         message.obj = args;
 
-        // If the interrogation is performed by the same thread as the main UI
-        // thread in this process, set the message as a static reference so
-        // after this call completes the same thread but in the interrogating
-        // client can handle the message to generate the result.
-        if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
-            AccessibilityInteractionClient.getInstanceForThread(
-                    interrogatingTid).setSameThreadMessage(message);
-        } else {
-            mHandler.sendMessage(message);
-        }
+        scheduleMessage(message, interrogatingPid, interrogatingTid);
     }
 
     private void focusSearchUiThread(Message message) {
@@ -582,31 +483,14 @@
                 }
             }
         } finally {
-            try {
-                mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-                applyAppScaleAndMagnificationSpecIfNeeded(next, spec);
-                // Recycle if called from another process. Specs are cached in the
-                // system process and obtained from a pool when read from parcel.
-                if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) {
-                    spec.recycle();
-                }
-                adjustIsVisibleToUserIfNeeded(next, interactiveRegion);
-                callback.setFindAccessibilityNodeInfoResult(next, interactionId);
-            } catch (RemoteException re) {
-                /* ignore - the other side will time out */
-            }
-
-            // Recycle if called from the same process. Regions are obtained in
-            // the system process and instantiated  when read from parcel.
-            if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) {
-                interactiveRegion.recycle();
-            }
+            updateInfoForViewportAndReturnFindNodeResult(
+                    next, callback, interactionId, spec, interactiveRegion);
         }
     }
 
     public void performAccessibilityActionClientThread(long accessibilityNodeId, int action,
             Bundle arguments, int interactionId,
-            IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
+            IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
             long interrogatingTid) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_PERFORM_ACCESSIBILITY_ACTION;
@@ -622,16 +506,7 @@
 
         message.obj = args;
 
-        // If the interrogation is performed by the same thread as the main UI
-        // thread in this process, set the message as a static reference so
-        // after this call completes the same thread but in the interrogating
-        // client can handle the message to generate the result.
-        if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
-            AccessibilityInteractionClient.getInstanceForThread(
-                    interrogatingTid).setSameThreadMessage(message);
-        } else {
-            mHandler.sendMessage(message);
-        }
+        scheduleMessage(message, interrogatingPid, interrogatingTid);
     }
 
     private void performAccessibilityActionUiThread(Message message) {
@@ -742,26 +617,6 @@
         }
     }
 
-    private void applyAppScaleAndMagnificationSpecIfNeeded(Point point,
-            MagnificationSpec spec) {
-        final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
-        if (!shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
-            return;
-        }
-
-        if (applicationScale != 1.0f) {
-            point.x *= applicationScale;
-            point.y *= applicationScale;
-        }
-
-        if (spec != null) {
-            point.x *= spec.scale;
-            point.y *= spec.scale;
-            point.x += (int) spec.offsetX;
-            point.y += (int) spec.offsetY;
-        }
-    }
-
     private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info,
             MagnificationSpec spec) {
         if (info == null) {
@@ -791,6 +646,25 @@
         info.setBoundsInParent(boundsInParent);
         info.setBoundsInScreen(boundsInScreen);
 
+        // Scale text locations if they are present
+        if (info.hasExtras()) {
+            Bundle extras = info.getExtras();
+            Parcelable[] textLocations =
+                    extras.getParcelableArray(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY);
+            if (textLocations != null) {
+                for (int i = 0; i < textLocations.length; i++) {
+                    // Unchecked cast - an app that puts other objects in this bundle with this
+                    // key will crash.
+                    RectF textLocation = ((RectF) textLocations[i]);
+                    textLocation.scale(applicationScale);
+                    if (spec != null) {
+                        textLocation.scale(spec.scale);
+                        textLocation.offset(spec.offsetX, spec.offsetY);
+                    }
+                }
+            }
+        }
+
         if (spec != null) {
             AttachInfo attachInfo = mViewRootImpl.mAttachInfo;
             if (attachInfo.mDisplay == null) {
@@ -829,6 +703,53 @@
         return (appScale != 1.0f || (spec != null && !spec.isNop()));
     }
 
+    private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos,
+            IAccessibilityInteractionConnectionCallback callback, int interactionId,
+            MagnificationSpec spec, Region interactiveRegion) {
+        try {
+            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
+            adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
+            callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+            infos.clear();
+        } catch (RemoteException re) {
+            /* ignore - the other side will time out */
+        } finally {
+            recycleMagnificationSpecAndRegionIfNeeded(spec, interactiveRegion);
+        }
+    }
+
+    private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info,
+            IAccessibilityInteractionConnectionCallback callback, int interactionId,
+            MagnificationSpec spec, Region interactiveRegion) {
+        try {
+            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+            adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+            callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+        } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+        } finally {
+            recycleMagnificationSpecAndRegionIfNeeded(spec, interactiveRegion);
+        }
+    }
+
+    private void recycleMagnificationSpecAndRegionIfNeeded(MagnificationSpec spec, Region region) {
+        if (android.os.Process.myPid() != Binder.getCallingPid()) {
+            // Specs are cached in the system process and obtained from a pool when read from
+            // a parcel, so only recycle the spec if called from another process.
+            if (spec != null) {
+                spec.recycle();
+            }
+        } else {
+            // Regions are obtained in the system process and instantiated when read from
+            // a parcel, so only recycle the region if caled from the same process.
+            if (region != null) {
+                region.recycle();
+            }
+        }
+    }
+
     private boolean handleClickableSpanActionUiThread(
             View view, int virtualDescendantId, Bundle arguments) {
         Parcelable span = arguments.getParcelable(ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN);
@@ -872,11 +793,18 @@
         private final ArrayList<View> mTempViewList = new ArrayList<View>();
 
         public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags,
-                List<AccessibilityNodeInfo> outInfos) {
+                List<AccessibilityNodeInfo> outInfos, Bundle arguments) {
             AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+            // Determine if we'll be populating extra data
+            final String extraDataRequested = (arguments == null) ? null
+                    : arguments.getString(AccessibilityNodeInfo.EXTRA_DATA_REQUESTED_KEY);
             if (provider == null) {
                 AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
                 if (root != null) {
+                    if (extraDataRequested != null) {
+                        view.addExtraDataToAccessibilityNodeInfo(
+                                root, extraDataRequested, arguments);
+                    }
                     outInfos.add(root);
                     if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
                         prefetchPredecessorsOfRealNode(view, outInfos);
@@ -889,14 +817,14 @@
                     }
                 }
             } else {
-                final AccessibilityNodeInfo root;
-                if (virtualViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                    root = provider.createAccessibilityNodeInfo(virtualViewId);
-                } else {
-                    root = provider.createAccessibilityNodeInfo(
-                            AccessibilityNodeProvider.HOST_VIEW_ID);
-                }
+                final int idForRoot = (virtualViewId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)
+                        ? AccessibilityNodeProvider.HOST_VIEW_ID : virtualViewId;
+                final AccessibilityNodeInfo root = provider.createAccessibilityNodeInfo(idForRoot);
                 if (root != null) {
+                    if (extraDataRequested != null) {
+                        provider.addExtraDataToAccessibilityNodeInfo(
+                                idForRoot, root, extraDataRequested, arguments);
+                    }
                     outInfos.add(root);
                     if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
                         prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
@@ -1202,12 +1130,12 @@
     }
 
     private class PrivateHandler extends Handler {
-        private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 1;
-        private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
-        private final static int MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID = 3;
-        private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4;
-        private final static int MSG_FIND_FOCUS = 5;
-        private final static int MSG_FOCUS_SEARCH = 6;
+        private static final int MSG_PERFORM_ACCESSIBILITY_ACTION = 1;
+        private static final int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
+        private static final int MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID = 3;
+        private static final int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4;
+        private static final int MSG_FIND_FOCUS = 5;
+        private static final int MSG_FOCUS_SEARCH = 6;
 
         public PrivateHandler(Looper looper) {
             super(looper);
@@ -1277,7 +1205,7 @@
         }
 
         @Override
-        public boolean apply(View view) {
+        public boolean test(View view) {
             if (view.getId() == mViewId && isShown(view)) {
                 mInfos.add(view.createAccessibilityNodeInfo());
             }
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 41a13cf..7fde8a6 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -52,7 +52,9 @@
     final Rect mFocusedRect = new Rect();
     final Rect mOtherRect = new Rect();
     final Rect mBestCandidateRect = new Rect();
-    final SequentialFocusComparator mSequentialFocusComparator = new SequentialFocusComparator();
+    private final UserSpecifiedFocusComparator mUserSpecifiedFocusComparator =
+            new UserSpecifiedFocusComparator();
+    private final FocusComparator mFocusComparator = new FocusComparator();
 
     private final ArrayList<View> mTempList = new ArrayList<View>();
 
@@ -225,12 +227,10 @@
             View focused, Rect focusedRect, int direction) {
         try {
             // Note: This sort is stable.
-            mSequentialFocusComparator.setRoot(root);
-            mSequentialFocusComparator.setIsLayoutRtl(root.isLayoutRtl());
-            mSequentialFocusComparator.setFocusables(focusables);
-            Collections.sort(focusables, mSequentialFocusComparator);
+            mUserSpecifiedFocusComparator.setFocusables(focusables);
+            Collections.sort(focusables, mUserSpecifiedFocusComparator);
         } finally {
-            mSequentialFocusComparator.recycle();
+            mUserSpecifiedFocusComparator.recycle();
         }
 
         final int count = focusables.size();
@@ -703,36 +703,80 @@
         return id != 0 && id != View.NO_ID;
     }
 
-    /**
-     * Sorts views according to their visual layout and geometry for default tab order.
-     * If views are part of a focus chain (nextFocusForwardId), then they are all grouped
-     * together. The head of the chain is used to determine the order of the chain and is
-     * first in the order and the tail of the chain is the last in the order. The views
-     * in the middle of the chain can be arbitrary order.
-     * This is used for sequential focus traversal.
-     */
-    private static final class SequentialFocusComparator implements Comparator<View> {
+    static FocusComparator getFocusComparator(ViewGroup root, boolean isRtl) {
+        FocusComparator comparator = getInstance().mFocusComparator;
+        comparator.setRoot(root);
+        comparator.setIsLayoutRtl(isRtl);
+        return comparator;
+    }
+
+    static final class FocusComparator implements Comparator<View> {
         private final Rect mFirstRect = new Rect();
         private final Rect mSecondRect = new Rect();
-        private ViewGroup mRoot;
+        private ViewGroup mRoot = null;
         private boolean mIsLayoutRtl;
-        private final SparseArray<View> mFocusables = new SparseArray<View>();
-        private final SparseBooleanArray mIsConnectedTo = new SparseBooleanArray();
-        private final ArrayMap<View, View> mHeadsOfChains = new ArrayMap<View, View>();
 
-        public void recycle() {
-            mRoot = null;
-            mFocusables.clear();
-            mHeadsOfChains.clear();
-            mIsConnectedTo.clear();
+        public void setIsLayoutRtl(boolean b) {
+            mIsLayoutRtl = b;
         }
 
         public void setRoot(ViewGroup root) {
             mRoot = root;
         }
 
-        public void setIsLayoutRtl(boolean b) {
-            mIsLayoutRtl = b;
+        public int compare(View first, View second) {
+            if (first == second) {
+                return 0;
+            }
+
+            getRect(first, mFirstRect);
+            getRect(second, mSecondRect);
+
+            if (mFirstRect.top < mSecondRect.top) {
+                return -1;
+            } else if (mFirstRect.top > mSecondRect.top) {
+                return 1;
+            } else if (mFirstRect.left < mSecondRect.left) {
+                return mIsLayoutRtl ? 1 : -1;
+            } else if (mFirstRect.left > mSecondRect.left) {
+                return mIsLayoutRtl ? -1 : 1;
+            } else if (mFirstRect.bottom < mSecondRect.bottom) {
+                return -1;
+            } else if (mFirstRect.bottom > mSecondRect.bottom) {
+                return 1;
+            } else if (mFirstRect.right < mSecondRect.right) {
+                return mIsLayoutRtl ? 1 : -1;
+            } else if (mFirstRect.right > mSecondRect.right) {
+                return mIsLayoutRtl ? -1 : 1;
+            } else {
+                // The view are distinct but completely coincident so we consider
+                // them equal for our purposes.  Since the sort is stable, this
+                // means that the views will retain their layout order relative to one another.
+                return 0;
+            }
+        }
+
+        private void getRect(View view, Rect rect) {
+            view.getDrawingRect(rect);
+            mRoot.offsetDescendantRectToMyCoords(view, rect);
+        }
+    }
+
+    /**
+     * Sorts views according to any explicitly-specified focus-chains. If there are no explicitly
+     * specified focus chains (eg. no nextFocusForward attributes defined), this should be a no-op.
+     */
+    private static final class UserSpecifiedFocusComparator implements Comparator<View> {
+        private final SparseArray<View> mFocusables = new SparseArray<View>();
+        private final SparseBooleanArray mIsConnectedTo = new SparseBooleanArray();
+        private final ArrayMap<View, View> mHeadsOfChains = new ArrayMap<View, View>();
+        private final ArrayMap<View, Integer> mOriginalOrdinal = new ArrayMap<>();
+
+        public void recycle() {
+            mFocusables.clear();
+            mHeadsOfChains.clear();
+            mIsConnectedTo.clear();
+            mOriginalOrdinal.clear();
         }
 
         public void setFocusables(ArrayList<View> focusables) {
@@ -755,6 +799,10 @@
                     setHeadOfChain(view);
                 }
             }
+
+            for (int i = 0; i < focusables.size(); ++i) {
+                mOriginalOrdinal.put(focusables.get(i), i);
+            }
         }
 
         private void setHeadOfChain(View head) {
@@ -793,44 +841,22 @@
                     return 1; // first is end of chain
                 }
             }
+            boolean involvesChain = false;
             if (firstHead != null) {
                 first = firstHead;
+                involvesChain = true;
             }
             if (secondHead != null) {
                 second = secondHead;
+                involvesChain = true;
             }
 
-            // First see if they belong to the same focus chain.
-            getRect(first, mFirstRect);
-            getRect(second, mSecondRect);
-
-            if (mFirstRect.top < mSecondRect.top) {
-                return -1;
-            } else if (mFirstRect.top > mSecondRect.top) {
-                return 1;
-            } else if (mFirstRect.left < mSecondRect.left) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (mFirstRect.left > mSecondRect.left) {
-                return mIsLayoutRtl ? -1 : 1;
-            } else if (mFirstRect.bottom < mSecondRect.bottom) {
-                return -1;
-            } else if (mFirstRect.bottom > mSecondRect.bottom) {
-                return 1;
-            } else if (mFirstRect.right < mSecondRect.right) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (mFirstRect.right > mSecondRect.right) {
-                return mIsLayoutRtl ? -1 : 1;
+            if (involvesChain) {
+                // keep original order between chains
+                return mOriginalOrdinal.get(first) < mOriginalOrdinal.get(second) ? -1 : 1;
             } else {
-                // The view are distinct but completely coincident so we consider
-                // them equal for our purposes.  Since the sort is stable, this
-                // means that the views will retain their layout order relative to one another.
                 return 0;
             }
         }
-
-        private void getRect(View view, Rect rect) {
-            view.getDrawingRect(rect);
-            mRoot.offsetDescendantRectToMyCoords(view, rect);
-        }
     }
 }
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 27c1dcb..52e53b0 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -502,6 +502,8 @@
         final boolean pointerUp =
                 (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP;
         final int skipIndex = pointerUp ? ev.getActionIndex() : -1;
+        final boolean isGeneratedGesture =
+                (ev.getFlags() & MotionEvent.FLAG_IS_GENERATED_GESTURE) != 0;
 
         // Determine focal point
         float sumX = 0, sumY = 0;
@@ -604,7 +606,8 @@
                 final int deltaX = (int) (focusX - mDownFocusX);
                 final int deltaY = (int) (focusY - mDownFocusY);
                 int distance = (deltaX * deltaX) + (deltaY * deltaY);
-                if (distance > mTouchSlopSquare) {
+                int slopSquare = isGeneratedGesture ? 0 : mTouchSlopSquare;
+                if (distance > slopSquare) {
                     handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                     mLastFocusX = focusX;
                     mLastFocusY = focusY;
@@ -613,7 +616,8 @@
                     mHandler.removeMessages(SHOW_PRESS);
                     mHandler.removeMessages(LONG_PRESS);
                 }
-                if (distance > mDoubleTapTouchSlopSquare) {
+                int doubleTapSlopSquare = isGeneratedGesture ? 0 : mDoubleTapTouchSlopSquare;
+                if (distance > doubleTapSlopSquare) {
                     mAlwaysInBiggerTapRegion = false;
                 }
             } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
@@ -761,7 +765,10 @@
 
         int deltaX = (int) firstDown.getX() - (int) secondDown.getX();
         int deltaY = (int) firstDown.getY() - (int) secondDown.getY();
-        return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare);
+        final boolean isGeneratedGesture =
+                (firstDown.getFlags() & MotionEvent.FLAG_IS_GENERATED_GESTURE) != 0;
+        int slopSquare = isGeneratedGesture ? 0 : mDoubleTapSlopSquare;
+        return (deltaX * deltaX + deltaY * deltaY < slopSquare);
     }
 
     private void dispatchLongPress() {
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index d59be02..2fe98c0 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -16,8 +16,6 @@
 
 package android.view;
 
-import android.graphics.Rect;
-
 /**
  * An interface to the PinnedStackController to update it of state changes, and to query
  * information based on the current state.
@@ -27,17 +25,7 @@
 interface IPinnedStackController {
 
     /**
-     * Notifies the controller that the user is currently interacting with the PIP.
-     */
-    oneway void setInInteractiveMode(boolean inInteractiveMode);
-
-    /**
-     * Notifies the controller that the PIP is currently minimized.
+     * Notifies the controller that the PiP is currently minimized.
      */
     oneway void setIsMinimized(boolean isMinimized);
-
-    /**
-     * Notifies the controller that the desired snap mode is to the closest edge.
-     */
-    oneway void setSnapToEdge(boolean snapToEdge);
 }
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index 3c348c5..c7340bf 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
 import android.view.IPinnedStackController;
 
 /**
@@ -33,10 +34,22 @@
     void onListenerRegistered(IPinnedStackController controller);
 
     /**
-     * Called when window manager decides to adjust the pinned stack bounds, or when the listener
-     * is first registered to allow the listener to synchronized its state with the controller.
+     * Called when the window manager has detected a change that would cause the movement bounds
+     * to be changed (ie. after configuration change, aspect ratio change, etc). It then provides
+     * the components that allow the listener to calculate the movement bounds itself. The
+     * {@param normalBounds} are also the default bounds that the PiP would be entered in its
+     * current state with the aspect ratio applied.
      */
-    void onBoundsChanged(boolean adjustedForIme);
+    void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds,
+            boolean fromImeAdjustement);
+
+    /**
+     * Called when window manager decides to adjust the pinned stack bounds because of the IME, or
+     * when the listener is first registered to allow the listener to synchronized its state with
+     * the controller.  This call will always be followed by a onMovementBoundsChanged() call
+     * with fromImeAdjustement set to true.
+     */
+    void onImeVisibilityChanged(boolean imeVisible, int imeHeight);
 
     /**
      * Called when window manager decides to adjust the minimized state, or when the listener
@@ -45,14 +58,6 @@
     void onMinimizedStateChanged(boolean isMinimized);
 
     /**
-     * Called when window manager decides to adjust the snap-to-edge state, which determines whether
-     * to snap only to the corners of the screen or to the closest edge.  It is called when the
-     * listener is first registered to allow the listener to synchronized its state with the
-     * controller.
-     */
-    void onSnapToEdgeStateChanged(boolean isSnapToEdge);
-
-    /**
      * Called when the set of actions for the current PiP activity changes, or when the listener
      * is first registered to allow the listener to synchronized its state with the controller.
      */
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c789f8c..dd76fcf 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -337,16 +337,6 @@
     void registerPinnedStackListener(int displayId, IPinnedStackListener listener);
 
     /**
-     * Returns the initial bounds that PIP will be shown when it is first started.
-     */
-    Rect getPictureInPictureDefaultBounds(int displayId);
-
-    /**
-     * Returns the bounds that the PIP can move on the screen in the current PIP state.
-     */
-    Rect getPictureInPictureMovementBounds(int displayId);
-
-    /**
      * Updates the dim layer used while resizing.
      *
      * @param visible Whether the dim layer should be visible.
diff --git a/core/java/android/view/Menu.java b/core/java/android/view/Menu.java
index 0c2e9cf..a8ea4dc 100644
--- a/core/java/android/view/Menu.java
+++ b/core/java/android/view/Menu.java
@@ -75,6 +75,13 @@
     static final int CATEGORY_SHIFT = 16;
 
     /**
+     * A mask of all supported modifiers for MenuItem's keyboard shortcuts
+     */
+    static final int SUPPORTED_MODIFIERS_MASK = KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON
+            | KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON
+            | KeyEvent.META_FUNCTION_ON;
+
+    /**
      * Value to use for group and item identifier integers when you don't care
      * about them.
      */
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 7a5c65f..6574bc0 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -305,7 +305,9 @@
         private CharSequence itemTitleCondensed;
         private int itemIconResId;
         private char itemAlphabeticShortcut;
+        private int itemAlphabeticModifiers;
         private char itemNumericShortcut;
+        private int itemNumericModifiers;
         /**
          * Sync to attrs.xml enum:
          * - 0: none
@@ -395,8 +397,14 @@
             itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0);
             itemAlphabeticShortcut =
                     getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_alphabeticShortcut));
+            itemAlphabeticModifiers =
+                    a.getInt(com.android.internal.R.styleable.MenuItem_alphabeticModifiers,
+                            KeyEvent.META_CTRL_ON);
             itemNumericShortcut =
                     getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_numericShortcut));
+            itemNumericModifiers =
+                    a.getInt(com.android.internal.R.styleable.MenuItem_numericModifiers,
+                            KeyEvent.META_CTRL_ON);
             if (a.hasValue(com.android.internal.R.styleable.MenuItem_checkable)) {
                 // Item has attribute checkable, use it
                 itemCheckable = a.getBoolean(com.android.internal.R.styleable.MenuItem_checkable, false) ? 1 : 0;
@@ -451,8 +459,8 @@
                 .setCheckable(itemCheckable >= 1)
                 .setTitleCondensed(itemTitleCondensed)
                 .setIcon(itemIconResId)
-                .setAlphabeticShortcut(itemAlphabeticShortcut)
-                .setNumericShortcut(itemNumericShortcut);
+                .setAlphabeticShortcut(itemAlphabeticShortcut, itemAlphabeticModifiers)
+                .setNumericShortcut(itemNumericShortcut, itemNumericModifiers);
 
             if (itemShowAsAction >= 0) {
                 item.setShowAsAction(itemShowAsAction);
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 3f8d089..6aaaedbe 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -261,12 +261,13 @@
     /**
      * Change both the numeric and alphabetic shortcut associated with this
      * item. Note that the shortcut will be triggered when the key that
-     * generates the given character is pressed along with the ctrl key.
-     * Also note that case is not significant and that alphabetic shortcut
-     * characters will be displayed in lower case.
+     * generates the given character is pressed along with the corresponding
+     * modifier key. The default modifier is  {@link KeyEvent#META_CTRL_ON} in
+     * case nothing is specified. Also note that case is not significant and
+     * that alphabetic shortcut characters will be handled in lower case.
      * <p>
      * See {@link Menu} for the menu types that support shortcuts.
-     * 
+     *
      * @param numericChar The numeric shortcut key. This is the shortcut when
      *        using a numeric (e.g., 12-key) keyboard.
      * @param alphaChar The alphabetic shortcut key. This is the shortcut when
@@ -276,6 +277,39 @@
     public MenuItem setShortcut(char numericChar, char alphaChar);
 
     /**
+     * Change both the numeric and alphabetic shortcut associated with this
+     * item. Note that the shortcut will be triggered when the key that
+     * generates the given character is pressed along with the corresponding
+     * modifier key. Also note that case is not significant and that alphabetic
+     * shortcut characters will be handled in lower case.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key. This is the shortcut when
+     *        using a numeric (e.g., 12-key) keyboard.
+     * @param numericModifiers The numeric modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The alphabetic modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    default public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        if ((alphaModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON
+                && (numericModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) {
+            return setShortcut(numericChar, alphaChar);
+        } else {
+            return this;
+        }
+    }
+
+    /**
      * Change the numeric shortcut associated with this item.
      * <p>
      * See {@link Menu} for the menu types that support shortcuts.
@@ -287,6 +321,27 @@
     public MenuItem setNumericShortcut(char numericChar);
 
     /**
+     * Change the numeric shortcut and modifiers associated with this item.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key.  This is the shortcut when
+     *                 using a 12-key (numeric) keyboard.
+     * @param numericModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    default public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        if ((numericModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) {
+            return setNumericShortcut(numericChar);
+        } else {
+            return this;
+        }
+    }
+
+    /**
      * Return the char for this menu item's numeric (12-key) shortcut.
      *
      * @return Numeric character to use as a shortcut.
@@ -294,15 +349,30 @@
     public char getNumericShortcut();
 
     /**
+     * Return the modifiers for this menu item's numeric (12-key) shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the numeric shortcut.
+     */
+    default public int getNumericModifiers() {
+        return KeyEvent.META_CTRL_ON;
+    }
+
+    /**
      * Change the alphabetic shortcut associated with this item. The shortcut
      * will be triggered when the key that generates the given character is
-     * pressed along with the ctrl key. Case is not significant and shortcut
-     * characters will be displayed in lower case. Note that menu items with
-     * the characters '\b' or '\n' as shortcuts will get triggered by the
-     * Delete key or Carriage Return key, respectively.
+     * pressed along with the corresponding modifier key. The default modifier
+     * is {@link KeyEvent#META_CTRL_ON} in case nothing is specified. Case is
+     * not significant and shortcut characters will be displayed in lower case.
+     * Note that menu items with the characters '\b' or '\n' as shortcuts will
+     * get triggered by the Delete key or Carriage Return key, respectively.
      * <p>
      * See {@link Menu} for the menu types that support shortcuts.
-     * 
+     *
      * @param alphaChar The alphabetic shortcut key. This is the shortcut when
      *        using a keyboard with alphabetic keys.
      * @return This Item so additional setters can be called.
@@ -310,6 +380,32 @@
     public MenuItem setAlphabeticShortcut(char alphaChar);
 
     /**
+     * Change the alphabetic shortcut associated with this item. The shortcut
+     * will be triggered when the key that generates the given character is
+     * pressed along with the modifier keys. Case is not significant and shortcut
+     * characters will be displayed in lower case. Note that menu items with
+     * the characters '\b' or '\n' as shortcuts will get triggered by the
+     * Delete key or Carriage Return key, respectively.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @param alphaModifiers The modifier associated with the shortcut. It should
+     *        be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON},
+     *        {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON},
+     *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
+     * @return This Item so additional setters can be called.
+     */
+    default public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+        if ((alphaModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) {
+            return setAlphabeticShortcut(alphaChar);
+        } else {
+            return this;
+        }
+    }
+
+    /**
      * Return the char for this menu item's alphabetic shortcut.
      *
      * @return Alphabetic character to use as a shortcut.
@@ -317,13 +413,27 @@
     public char getAlphabeticShortcut();
 
     /**
+     * Return the modifier for this menu item's alphabetic shortcut.
+     * The modifier is a combination of {@link KeyEvent#META_META_ON},
+     * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON},
+     * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON},
+     * {@link KeyEvent#META_FUNCTION_ON}.
+     * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON}
+     *
+     * @return Modifier associated with the keyboard shortcut.
+     */
+    default public int getAlphabeticModifiers() {
+        return KeyEvent.META_CTRL_ON;
+    }
+
+    /**
      * Control whether this item can display a check mark. Setting this does
      * not actually display a check mark (see {@link #setChecked} for that);
      * rather, it ensures there is room in the item in which to display a
      * check mark.
      * <p>
      * See {@link Menu} for the menu types that support check marks.
-     * 
+     *
      * @param checkable Set to true to allow a check mark, false to
      *            disallow. The default is false.
      * @see #setChecked
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 2316b38..2129039 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -186,7 +186,7 @@
      * Bit mask of the parts of the action code that are the action itself.
      */
     public static final int ACTION_MASK             = 0xff;
-    
+
     /**
      * Constant for {@link #getActionMasked}: A pressed gesture has started, the
      * motion contains the initial starting location.
@@ -197,14 +197,14 @@
      * </p>
      */
     public static final int ACTION_DOWN             = 0;
-    
+
     /**
      * Constant for {@link #getActionMasked}: A pressed gesture has finished, the
      * motion contains the final release location as well as any intermediate
      * points since the last down or move event.
      */
     public static final int ACTION_UP               = 1;
-    
+
     /**
      * Constant for {@link #getActionMasked}: A change has happened during a
      * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}).
@@ -212,14 +212,14 @@
      * points since the last down or move event.
      */
     public static final int ACTION_MOVE             = 2;
-    
+
     /**
      * Constant for {@link #getActionMasked}: The current gesture has been aborted.
      * You will not receive any more points in it.  You should treat this as
      * an up event, but not perform any action that you normally would.
      */
     public static final int ACTION_CANCEL           = 3;
-    
+
     /**
      * Constant for {@link #getActionMasked}: A movement has happened outside of the
      * normal bounds of the UI element.  This does not provide a full gesture,
@@ -237,7 +237,7 @@
      * </p>
      */
     public static final int ACTION_POINTER_DOWN     = 5;
-    
+
     /**
      * Constant for {@link #getActionMasked}: A non-primary pointer has gone up.
      * <p>
@@ -343,7 +343,7 @@
      * @see #getActionIndex
      */
     public static final int ACTION_POINTER_INDEX_MASK  = 0xff00;
-    
+
     /**
      * Bit shift for the action bits holding the pointer index as
      * defined by {@link #ACTION_POINTER_INDEX_MASK}.
@@ -358,56 +358,56 @@
      */
     @Deprecated
     public static final int ACTION_POINTER_1_DOWN   = ACTION_POINTER_DOWN | 0x0000;
-    
+
     /**
      * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
      * data index associated with {@link #ACTION_POINTER_DOWN}.
      */
     @Deprecated
     public static final int ACTION_POINTER_2_DOWN   = ACTION_POINTER_DOWN | 0x0100;
-    
+
     /**
      * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
      * data index associated with {@link #ACTION_POINTER_DOWN}.
      */
     @Deprecated
     public static final int ACTION_POINTER_3_DOWN   = ACTION_POINTER_DOWN | 0x0200;
-    
+
     /**
      * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
      * data index associated with {@link #ACTION_POINTER_UP}.
      */
     @Deprecated
     public static final int ACTION_POINTER_1_UP     = ACTION_POINTER_UP | 0x0000;
-    
+
     /**
      * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
      * data index associated with {@link #ACTION_POINTER_UP}.
      */
     @Deprecated
     public static final int ACTION_POINTER_2_UP     = ACTION_POINTER_UP | 0x0100;
-    
+
     /**
      * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the
      * data index associated with {@link #ACTION_POINTER_UP}.
      */
     @Deprecated
     public static final int ACTION_POINTER_3_UP     = ACTION_POINTER_UP | 0x0200;
-    
+
     /**
      * @deprecated Renamed to {@link #ACTION_POINTER_INDEX_MASK} to match
      * the actual data contained in these bits.
      */
     @Deprecated
     public static final int ACTION_POINTER_ID_MASK  = 0xff00;
-    
+
     /**
      * @deprecated Renamed to {@link #ACTION_POINTER_INDEX_SHIFT} to match
      * the actual data contained in these bits.
      */
     @Deprecated
     public static final int ACTION_POINTER_ID_SHIFT = 8;
-    
+
     /**
      * This flag indicates that the window that received this motion event is partly
      * or wholly obscured by another visible window above it.  This flag is set to true
@@ -444,6 +444,14 @@
     public static final int FLAG_HOVER_EXIT_PENDING = 0x4;
 
     /**
+     * This flag indicates that the event has been generated by a gesture generator. It
+     * provides a hint to the GestureDector to not apply any touch slop.
+     *
+     * @hide
+     */
+    public static final int FLAG_IS_GENERATED_GESTURE = 0x8;
+
+    /**
      * Private flag that indicates when the system has detected that this motion event
      * may be inconsistent with respect to the sequence of previously delivered motion events,
      * such as when a pointer move event is sent but the pointer is not down.
@@ -1582,9 +1590,9 @@
      * Create a new MotionEvent, filling in all of the basic values that
      * define the motion.
      *
-     * @param downTime The time (in ms) when the user originally pressed down to start 
+     * @param downTime The time (in ms) when the user originally pressed down to start
      * a stream of position events.  This must be obtained from {@link SystemClock#uptimeMillis()}.
-     * @param eventTime The the time (in ms) when this specific event was generated.  This 
+     * @param eventTime The the time (in ms) when this specific event was generated.  This
      * must be obtained from {@link SystemClock#uptimeMillis()}.
      * @param action The kind of action being performed, such as {@link #ACTION_DOWN}.
      * @param pointerCount The number of pointers that will be in this event.
@@ -1623,7 +1631,7 @@
     /**
      * Create a new MotionEvent, filling in all of the basic values that
      * define the motion.
-     * 
+     *
      * @param downTime The time (in ms) when the user originally pressed down to start
      * a stream of position events.  This must be obtained from {@link SystemClock#uptimeMillis()}.
      * @param eventTime The the time (in ms) when this specific event was generated.  This
@@ -1751,7 +1759,7 @@
      * numbers are arbitrary and you shouldn't depend on the values.
      * @param edgeFlags A bitfield indicating which edges, if any, were touched by this
      * MotionEvent.
-     * 
+     *
      * @deprecated Use {@link #obtain(long, long, int, float, float, float, float, int, float, float, int, int)}
      * instead.
      */
@@ -2057,7 +2065,7 @@
     public final float getSize() {
         return nativeGetAxisValue(mNativePtr, AXIS_SIZE, 0, HISTORY_CURRENT);
     }
-    
+
     /**
      * {@link #getTouchMajor(int)} for the first pointer index (may be an
      * arbitrary pointer identifier).
@@ -2077,7 +2085,7 @@
     public final float getTouchMinor() {
         return nativeGetAxisValue(mNativePtr, AXIS_TOUCH_MINOR, 0, HISTORY_CURRENT);
     }
-    
+
     /**
      * {@link #getToolMajor(int)} for the first pointer index (may be an
      * arbitrary pointer identifier).
@@ -2161,7 +2169,7 @@
 
     /**
      * Given a pointer identifier, find the index of its data in the event.
-     * 
+     *
      * @param pointerId The identifier of the pointer to be found.
      * @return Returns either the index of the pointer (for use with
      * {@link #getX(int)} et al.), or -1 if there is no data available for
@@ -2175,8 +2183,8 @@
      * Returns the X coordinate of this event for the given pointer
      * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
      * identifier for this index).
-     * Whole numbers are pixels; the 
-     * value may have a fraction for input devices that are sub-pixel precise. 
+     * Whole numbers are pixels; the
+     * value may have a fraction for input devices that are sub-pixel precise.
      * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      *
@@ -2235,7 +2243,7 @@
     public final float getSize(int pointerIndex) {
         return nativeGetAxisValue(mNativePtr, AXIS_SIZE, pointerIndex, HISTORY_CURRENT);
     }
-    
+
     /**
      * Returns the length of the major axis of an ellipse that describes the touch
      * area at the point of contact for the given pointer
@@ -2249,7 +2257,7 @@
     public final float getTouchMajor(int pointerIndex) {
         return nativeGetAxisValue(mNativePtr, AXIS_TOUCH_MAJOR, pointerIndex, HISTORY_CURRENT);
     }
-    
+
     /**
      * Returns the length of the minor axis of an ellipse that describes the touch
      * area at the point of contact for the given pointer
@@ -2263,7 +2271,7 @@
     public final float getTouchMinor(int pointerIndex) {
         return nativeGetAxisValue(mNativePtr, AXIS_TOUCH_MINOR, pointerIndex, HISTORY_CURRENT);
     }
-    
+
     /**
      * Returns the length of the major axis of an ellipse that describes the size of
      * the approaching tool for the given pointer
@@ -2279,7 +2287,7 @@
     public final float getToolMajor(int pointerIndex) {
         return nativeGetAxisValue(mNativePtr, AXIS_TOOL_MAJOR, pointerIndex, HISTORY_CURRENT);
     }
-    
+
     /**
      * Returns the length of the minor axis of an ellipse that describes the size of
      * the approaching tool for the given pointer
@@ -2295,7 +2303,7 @@
     public final float getToolMinor(int pointerIndex) {
         return nativeGetAxisValue(mNativePtr, AXIS_TOOL_MINOR, pointerIndex, HISTORY_CURRENT);
     }
-    
+
     /**
      * Returns the orientation of the touch area and tool area in radians clockwise from vertical
      * for the given pointer <em>index</em> (use {@link #getPointerId(int)} to find the pointer
@@ -2334,7 +2342,7 @@
     /**
      * Populates a {@link PointerCoords} object with pointer coordinate data for
      * the specified pointer index.
-     * 
+     *
      * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param outPointerCoords The pointer coordinate object to populate.
@@ -2622,7 +2630,7 @@
     public final float getHistoricalTouchMinor(int pos) {
         return nativeGetAxisValue(mNativePtr, AXIS_TOUCH_MINOR, 0, pos);
     }
-    
+
     /**
      * {@link #getHistoricalToolMajor(int, int)} for the first pointer index (may be an
      * arbitrary pointer identifier).
@@ -2652,7 +2660,7 @@
     public final float getHistoricalToolMinor(int pos) {
         return nativeGetAxisValue(mNativePtr, AXIS_TOOL_MINOR, 0, pos);
     }
-    
+
     /**
      * {@link #getHistoricalOrientation(int, int)} for the first pointer index (may be an
      * arbitrary pointer identifier).
@@ -2730,7 +2738,7 @@
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
-     * 
+     *
      * @see #getHistorySize
      * @see #getPressure(int)
      * @see #AXIS_PRESSURE
@@ -2748,7 +2756,7 @@
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
-     * 
+     *
      * @see #getHistorySize
      * @see #getSize(int)
      * @see #AXIS_SIZE
@@ -2756,7 +2764,7 @@
     public final float getHistoricalSize(int pointerIndex, int pos) {
         return nativeGetAxisValue(mNativePtr, AXIS_SIZE, pointerIndex, pos);
     }
-    
+
     /**
      * Returns a historical touch major axis coordinate, as per {@link #getTouchMajor(int)}, that
      * occurred between this event and the previous event for the given pointer.
@@ -2766,7 +2774,7 @@
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
-     * 
+     *
      * @see #getHistorySize
      * @see #getTouchMajor(int)
      * @see #AXIS_TOUCH_MAJOR
@@ -2784,7 +2792,7 @@
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
-     * 
+     *
      * @see #getHistorySize
      * @see #getTouchMinor(int)
      * @see #AXIS_TOUCH_MINOR
@@ -2802,7 +2810,7 @@
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
-     * 
+     *
      * @see #getHistorySize
      * @see #getToolMajor(int)
      * @see #AXIS_TOOL_MAJOR
@@ -2820,7 +2828,7 @@
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
-     * 
+     *
      * @see #getHistorySize
      * @see #getToolMinor(int)
      * @see #AXIS_TOOL_MINOR
@@ -2838,7 +2846,7 @@
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
-     * 
+     *
      * @see #getHistorySize
      * @see #getOrientation(int)
      * @see #AXIS_ORIENTATION
@@ -2871,13 +2879,13 @@
      * as per {@link #getPointerCoords}, that occurred between this event and the previous
      * event for the given pointer.
      * Only applies to ACTION_MOVE events.
-     * 
+     *
      * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
      * (the first pointer that is down) to {@link #getPointerCount()}-1.
      * @param pos Which historical value to return; must be less than
      * {@link #getHistorySize}
      * @param outPointerCoords The pointer coordinate object to populate.
-     * 
+     *
      * @see #getHistorySize
      * @see #getPointerCoords
      * @see PointerCoords
@@ -2886,7 +2894,7 @@
             PointerCoords outPointerCoords) {
         nativeGetPointerCoords(mNativePtr, pointerIndex, pos, outPointerCoords);
     }
-    
+
     /**
      * Returns a bitfield indicating which edges, if any, were touched by this
      * MotionEvent. For touch events, clients can use this to determine if the
@@ -2943,7 +2951,7 @@
         float oldY = getY();
         offsetLocation(x - oldX, y - oldY);
     }
-    
+
     /**
      * Applies a transformation matrix to all of the points in the event.
      *
@@ -3427,11 +3435,11 @@
 
     /**
      * Transfer object for pointer coordinates.
-     * 
+     *
      * Objects of this type can be used to specify the pointer coordinates when
      * creating new {@link MotionEvent} objects and to query pointer coordinates
      * in bulk.
-     * 
+     *
      * Refer to {@link InputDevice} for information about how different kinds of
      * input devices and sources represent pointer coordinates.
      */
@@ -3471,14 +3479,14 @@
          * @see MotionEvent#AXIS_X
          */
         public float x;
-        
+
         /**
          * The Y component of the pointer movement.
          *
          * @see MotionEvent#AXIS_Y
          */
         public float y;
-        
+
         /**
          * A normalized value that describes the pressure applied to the device
          * by a finger or other tool.
@@ -3489,7 +3497,7 @@
          * @see MotionEvent#AXIS_PRESSURE
          */
         public float pressure;
-        
+
         /**
          * A normalized value that describes the approximate size of the pointer touch area
          * in relation to the maximum detectable size of the device.
@@ -3502,7 +3510,7 @@
          * @see MotionEvent#AXIS_SIZE
          */
         public float size;
-        
+
         /**
          * The length of the major axis of an ellipse that describes the touch area at
          * the point of contact.
@@ -3512,7 +3520,7 @@
          * @see MotionEvent#AXIS_TOUCH_MAJOR
          */
         public float touchMajor;
-        
+
         /**
          * The length of the minor axis of an ellipse that describes the touch area at
          * the point of contact.
@@ -3522,7 +3530,7 @@
          * @see MotionEvent#AXIS_TOUCH_MINOR
          */
         public float touchMinor;
-        
+
         /**
          * The length of the major axis of an ellipse that describes the size of
          * the approaching tool.
@@ -3534,7 +3542,7 @@
          * @see MotionEvent#AXIS_TOOL_MAJOR
          */
         public float toolMajor;
-        
+
         /**
          * The length of the minor axis of an ellipse that describes the size of
          * the approaching tool.
@@ -3546,7 +3554,7 @@
          * @see MotionEvent#AXIS_TOOL_MINOR
          */
         public float toolMinor;
-        
+
         /**
          * The orientation of the touch area and tool area in radians clockwise from vertical.
          * An angle of 0 radians indicates that the major axis of contact is oriented
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 0da710a..c3d3f39 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.Nullable;
+import android.app.Notification;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Outline;
@@ -39,7 +40,7 @@
  */
 @RemoteViews.RemoteView
 public class NotificationHeaderView extends ViewGroup {
-    public static final int NO_COLOR = -1;
+    public static final int NO_COLOR = Notification.COLOR_INVALID;
     private final int mChildMinWidth;
     private final int mContentEndMargin;
     private View mAppName;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e2eee95..b06c3fd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,12 +16,6 @@
 
 package android.view;
 
-import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
-import static android.os.Build.VERSION_CODES.KITKAT;
-import static android.os.Build.VERSION_CODES.M;
-import static android.os.Build.VERSION_CODES.N;
-
 import static java.lang.Math.max;
 
 import android.animation.AnimatorInflater;
@@ -67,7 +61,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManagerGlobal;
-import android.os.Build.VERSION_CODES;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -106,7 +100,6 @@
 import android.view.autofill.AutoFillManager;
 import android.view.autofill.AutoFillType;
 import android.view.autofill.AutoFillValue;
-import android.view.autofill.VirtualViewDelegate;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
@@ -115,7 +108,6 @@
 import android.widget.ScrollBarDrawable;
 
 import com.android.internal.R;
-import com.android.internal.util.Predicate;
 import com.android.internal.view.TooltipPopup;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.widget.ScrollBarUtils;
@@ -140,6 +132,7 @@
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
 
 /**
  * <p>
@@ -857,6 +850,14 @@
      */
     static boolean sCascadedDragDrop;
 
+    /**
+     * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable
+     * to determine things like whether or not to permit item click events. We can't break
+     * apps that do this just because more things (clickable things) are now auto-focusable
+     * and they would get different results, so give old behavior to old apps.
+     */
+    static boolean sHasFocusableExcludeAutoFocusable;
+
     /** @hide */
     @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
     @Retention(RetentionPolicy.SOURCE)
@@ -4143,40 +4144,43 @@
             final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
 
             // Older apps may need this compatibility hack for measurement.
-            sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1;
+            sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
 
             // Older apps expect onMeasure() to always be called on a layout pass, regardless
             // of whether a layout was requested on that View.
-            sIgnoreMeasureCache = targetSdkVersion < KITKAT;
+            sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT;
 
-            Canvas.sCompatibilityRestore = targetSdkVersion < M;
+            Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M;
 
             // In M and newer, our widgets can pass a "hint" value in the size
             // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers
             // know what the expected parent size is going to be, so e.g. list items can size
             // themselves at 1/3 the size of their container. It breaks older apps though,
             // specifically apps that use some popular open source libraries.
-            sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M;
+            sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M;
 
             // Old versions of the platform would give different results from
             // LinearLayout measurement passes using EXACTLY and non-EXACTLY
             // modes, so we always need to run an additional EXACTLY pass.
-            sAlwaysRemeasureExactly = targetSdkVersion <= M;
+            sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M;
 
             // Prior to N, layout params could change without requiring a
             // subsequent call to setLayoutParams() and they would usually
             // work. Partial layout breaks this assumption.
-            sLayoutParamsAlwaysChanged = targetSdkVersion <= M;
+            sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M;
 
             // Prior to N, TextureView would silently ignore calls to setBackground/setForeground.
             // On N+, we throw, but that breaks compatibility with apps that use these methods.
-            sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;
+            sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M;
 
             // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs
             // in apps so we target check it to avoid breaking existing apps.
-            sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N;
+            sPreserveMarginParamsInLayoutParamConversion =
+                    targetSdkVersion >= Build.VERSION_CODES.N;
 
-            sCascadedDragDrop = targetSdkVersion < N;
+            sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N;
+
+            sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O;
 
             sCompatibilityDone = true;
         }
@@ -4525,7 +4529,7 @@
                     break;
                 //noinspection deprecation
                 case R.styleable.View_fadingEdge:
-                    if (targetSdkVersion >= ICE_CREAM_SANDWICH) {
+                    if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                         // Ignore the attribute starting with ICS
                         break;
                     }
@@ -4663,27 +4667,27 @@
                             PROVIDER_BACKGROUND));
                     break;
                 case R.styleable.View_foreground:
-                    if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) {
+                    if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
                         setForeground(a.getDrawable(attr));
                     }
                     break;
                 case R.styleable.View_foregroundGravity:
-                    if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) {
+                    if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
                         setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY));
                     }
                     break;
                 case R.styleable.View_foregroundTintMode:
-                    if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) {
+                    if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
                         setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null));
                     }
                     break;
                 case R.styleable.View_foregroundTint:
-                    if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) {
+                    if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
                         setForegroundTintList(a.getColorStateList(attr));
                     }
                     break;
                 case R.styleable.View_foregroundInsidePadding:
-                    if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) {
+                    if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
                         if (mForegroundInfo == null) {
                             mForegroundInfo = new ForegroundInfo();
                         }
@@ -6121,9 +6125,7 @@
 
             if (mParent != null) {
                 mParent.requestChildFocus(this, this);
-                if (mParent instanceof ViewGroup) {
-                    ((ViewGroup) mParent).setDefaultFocus(this);
-                }
+                setFocusedInCluster();
             }
 
             if (mAttachInfo != null) {
@@ -6344,26 +6346,51 @@
 
     /**
      * Returns true if this view is focusable or if it contains a reachable View
-     * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()"
-     * is a View whose parents do not block descendants focus.
-     *
+     * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()"
+     * is a view whose parents do not block descendants focus.
      * Only {@link #VISIBLE} views are considered focusable.
      *
-     * @return True if the view is focusable or if the view contains a focusable
-     *         View, false otherwise.
+     * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable
+     * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}.
+     * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of
+     * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return
+     * {@code false} for views not explicitly marked as focusable.
+     * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O}
+     * behavior.</p>
+     *
+     * @return {@code true} if the view is focusable or if the view contains a focusable
+     *         view, {@code false} otherwise
      *
      * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS
      * @see ViewGroup#getTouchscreenBlocksFocus()
+     * @see #hasExplicitFocusable()
      */
     public boolean hasFocusable() {
-        return hasFocusable(true);
+        return hasFocusable(!sHasFocusableExcludeAutoFocusable, false);
     }
 
     /**
-     * @hide pending determination of whether this should be public or not.
-     * Currently used for compatibility with old focusability expectations in ListView.
+     * Returns true if this view is focusable or if it contains a reachable View
+     * for which {@link #hasExplicitFocusable()} returns {@code true}.
+     * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus.
+     * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return
+     * {@link #FOCUSABLE} are considered focusable.
+     *
+     * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of
+     * {@link #hasFocusable()} in that only views explicitly set focusable will cause
+     * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves
+     * to focusable will not.</p>
+     *
+     * @return {@code true} if the view is focusable or if the view contains a focusable
+     *         view, {@code false} otherwise
+     *
+     * @see #hasFocusable()
      */
-    public boolean hasFocusable(boolean allowAutoFocus) {
+    public boolean hasExplicitFocusable() {
+        return hasFocusable(false, true);
+    }
+
+    boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
         if (!isFocusableInTouchMode()) {
             for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) {
                 final ViewGroup g = (ViewGroup) p;
@@ -6424,9 +6451,7 @@
         if (isAutoFillable()) {
             AutoFillManager afm = getAutoFillManager();
             if (afm != null) {
-                afm.updateAutoFillInput(this, gainFocus
-                        ? AutoFillManager.FLAG_UPDATE_UI_SHOW
-                        : AutoFillManager.FLAG_UPDATE_UI_HIDE);
+                afm.focusChanged(this, gainFocus);
             }
         }
 
@@ -6886,10 +6911,16 @@
     /**
      * Called when assist structure is being retrieved from a view as part of an auto-fill request.
      *
-     * <p>The structure must be filled according to the request type, which is set in the
-     * {@code flags} parameter - see the documentation on each flag for more details.
+     * <p>When implementing this method, subclasses must also:
      *
-     * @param structure Fill in with structured view data.  The default implementation
+     * <ol>
+     * <li>Implement {@link #autoFill(AutoFillValue)}, {@link #getAutoFillType()}
+     * and {@link #getAutoFillValue()}.
+     * <li>Call {@link android.view.autofill.AutoFillManager#virtualValueChanged(View, int,
+     * AutoFillValue)} when its value changed.
+     * </ol>
+     *
+     * @param structure Fill in with structured view data. The default implementation
      * fills in all data that can be inferred from the view itself.
      * @param flags optional flags (currently {@code 0}).
      */
@@ -6916,10 +6947,16 @@
         }
 
         if (forAutoFill) {
-            // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to
-            // reuse the accessibility id to save space.
-            structure.setAutoFillId(getAccessibilityViewId());
-            structure.setAutoFillType(getAutoFillType());
+            final AutoFillType autoFillType = getAutoFillType();
+            // Don't need to fill auto-fill info if view does not support it.
+            // For example, only TextViews that are editable support auto-fill
+            if (autoFillType != null) {
+                // The auto-fill id needs to be unique, but its value doesn't matter, so it's better
+                // to reuse the accessibility id to save space.
+                structure.setAutoFillId(getAccessibilityViewId());
+                structure.setAutoFillType(autoFillType);
+                structure.setAutoFillValue(getAutoFillValue());
+            }
         }
 
         structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
@@ -6979,12 +7016,22 @@
      * Called when assist structure is being retrieved from a view as part of an auto-fill request
      * to generate additional virtual structure under this view.
      *
-     * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to
+     * <p>The default implementation uses {@link #getAccessibilityNodeProvider()} to try to
      * generate this from the view's virtual accessibility nodes, if any. You can override this
      * for a more optimal implementation providing this data.
      *
-     * <p>The structure must be filled according to the request type, which is set in the
-     * {@code flags} parameter - see the documentation on each flag for more details.
+     * <p>When implementing this method, subclasses must follow the rules below:
+     *
+     * <ol>
+     * <li>Also implement {@link #autoFillVirtual(int, AutoFillValue)} to auto-fill the virtual
+     * children.
+     * <li>Call {@link android.view.autofill.AutoFillManager#virtualFocusChanged(View, int, Rect,
+     * boolean)} when the focus inside the view changed.
+     * <li>Call {@link android.view.autofill.AutoFillManager#virtualValueChanged(View, int,
+     * AutoFillValue)} when the value of a child changed.
+     * <li>Call {@link android.view.autofill.AutoFillManager#reset()} when the auto-fill context
+     * of the view structure changed.
+     * </ol>
      *
      * @param structure Fill in with structured view data.
      * @param flags optional flags (currently {@code 0}).
@@ -7008,29 +7055,17 @@
     }
 
     /**
-     * Gets the {@link VirtualViewDelegate} responsible for auto-filling the virtual children of
-     * this view.
-     *
-     * <p>By default returns {@code null} but should be overridden when view provides a virtual
-     * hierachy on {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}.
-     */
-    @Nullable
-    public VirtualViewDelegate getAutoFillVirtualViewDelegate(
-            @SuppressWarnings("unused") VirtualViewDelegate.Callback callback) {
-        return null;
-    }
-
-    /**
      * Automatically fills the content of this view with the {@code value}.
      *
-     * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()} to
-     * support the AutoFill Framework.
+     * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()},
+     * {@link #getAutoFillValue()}, and {@link #onProvideAutoFillStructure(ViewStructure, int)}
+     * to support the AutoFill Framework.
      *
      * <p>Typically, it is implemented by:
      *
      * <ol>
-     * <li>Call the proper getter method on {@link AutoFillValue} to fetch the actual value.
-     * <li>Pass the actual value to the equivalent setter in the view.
+     * <li>Calling the proper getter method on {@link AutoFillValue} to fetch the actual value.
+     * <li>Passing the actual value to the equivalent setter in the view.
      * <ol>
      *
      * <p>For example, a text-field view would call:
@@ -7041,15 +7076,29 @@
      *     setText(text);
      * }
      * </pre>
+     *
+     * @param value value to be auto-filled.
      */
     public void autoFill(@SuppressWarnings("unused") AutoFillValue value) {
     }
 
     /**
-     * Describes the auto-fill type that should be used on calls to
-     * {@link #autoFill(AutoFillValue)} and
-     * {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     * Automatically fills the content of a virtual view with the {@code value}
      *
+     * <p>See {@link #autoFill(AutoFillValue)} and
+     * {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)} for more info.
+     *
+     * @param value value to be auto-filled.
+     * @param virtualId id identifying the virtual child inside the custom view.
+     */
+    public void autoFillVirtual(@SuppressWarnings("unused") int virtualId,
+            @SuppressWarnings("unused") AutoFillValue value) {
+    }
+
+    /**
+     * Describes the auto-fill type that should be used on calls to
+     * {@link #autoFill(AutoFillValue)} and {@link #autoFillVirtual(int, AutoFillValue)}.
+
      * <p>By default returns {@code null}, but views should override it (and
      * {@link #autoFill(AutoFillValue)} to support the AutoFill Framework.
      */
@@ -7058,6 +7107,18 @@
         return null;
     }
 
+    /**
+     * Gets the {@link View}'s current auto-fill value.
+     *
+     * <p>By default returns {@code null}, but views should override it,
+     * {@link #autoFill(AutoFillValue)}, and {@link #getAutoFillType()} to support the AutoFill
+     * Framework.
+     */
+    @Nullable
+    public AutoFillValue getAutoFillValue() {
+        return null;
+    }
+
     @Nullable
     private AutoFillManager getAutoFillManager() {
         return mContext.getSystemService(AutoFillManager.class);
@@ -7156,6 +7217,9 @@
         boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
         if (!blocked) {
             if (forAutoFill) {
+                // The auto-fill id needs to be unique, but its value doesn't matter,
+                // so it's better to reuse the accessibility id to save space.
+                structure.setAutoFillId(getAccessibilityViewId());
                 // NOTE: flags are not currently supported, hence 0
                 onProvideAutoFillStructure(structure, 0);
                 onProvideAutoFillVirtualStructure(structure, 0);
@@ -7318,6 +7382,25 @@
     }
 
     /**
+     * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
+     * additional data.
+     * <p>
+     * This method only needs overloading if the node is marked as having extra data available.
+     * </p>
+     *
+     * @param info The info to which to add the extra data
+     * @param extraDataKey A key specifying the type of extra data to add to the info. The
+     *                     extra data should be added to the {@link Bundle} returned by
+     *                     the info's {@link AccessibilityNodeInfo#getExtras} method.
+     * @param arguments A {@link Bundle} holding any arguments relevant for this request.
+     *
+     * @see AccessibilityNodeInfo#setExtraAvailableData
+     */
+    public void addExtraDataToAccessibilityNodeInfo(
+            AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+    }
+
+    /**
      * Determine the order in which this view will be drawn relative to its siblings for a11y
      *
      * @param info The info whose drawing order should be populated
@@ -8645,7 +8728,7 @@
     @ResolvedLayoutDir
     public int getLayoutDirection() {
         final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
-        if (targetSdkVersion < JELLY_BEAN_MR1) {
+        if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
             mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
             return LAYOUT_DIRECTION_RESOLVED_DEFAULT;
         }
@@ -9160,6 +9243,19 @@
     }
 
     /**
+     * Sets this View as the one which receives focus the next time cluster navigation jumps
+     * to the cluster containing this View. This does NOT change focus even if the cluster
+     * containing this view is current.
+     *
+     * @hide
+     */
+    public void setFocusedInCluster() {
+        if (mParent instanceof ViewGroup) {
+            ((ViewGroup) mParent).setFocusInCluster(this);
+        }
+    }
+
+    /**
      * Returns whether this View should receive focus when the focus is restored for the view
      * hierarchy containing this view.
      * <p>
@@ -9205,7 +9301,7 @@
             if (isFocusedByDefault) {
                 ((ViewGroup) mParent).setDefaultFocus(this);
             } else {
-                ((ViewGroup) mParent).cleanDefaultFocus(this);
+                ((ViewGroup) mParent).clearDefaultFocus(this);
             }
         }
     }
@@ -9291,7 +9387,7 @@
                 final int id = mID;
                 return root.findViewByPredicateInsideOut(this, new Predicate<View>() {
                     @Override
-                    public boolean apply(View t) {
+                    public boolean test(View t) {
                         return t.mNextFocusForwardId == id;
                     }
                 });
@@ -9585,15 +9681,27 @@
     }
 
     /**
+     * Public for testing. This will request focus for whichever View was last focused within this
+     * cluster before a focus-jump out of it.
+     *
+     * @hide
+     */
+    public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
+        // Prioritize focusableByDefault over algorithmic focus selection.
+        if (restoreDefaultFocus()) {
+            return true;
+        }
+        return requestFocus(direction);
+    }
+
+    /**
      * Gives focus to the default-focus view in the view hierarchy that has this view as a root.
      * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}.
-     * Nested keyboard navigation clusters are excluded from the hierarchy.
      *
-     * @param direction The direction of the focus
      * @return Whether this view or one of its descendants actually took focus
      */
-    public boolean restoreDefaultFocus(@FocusDirection int direction) {
-        return requestFocus(direction);
+    public boolean restoreDefaultFocus() {
+        return requestFocus(View.FOCUS_DOWN);
     }
 
     /**
@@ -15696,7 +15804,7 @@
      */
     private boolean isRtlCompatibilityMode() {
         final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
-        return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport();
+        return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport();
     }
 
     /**
@@ -19942,9 +20050,9 @@
      * @return the view of the specified id, null if cannot be found
      * @hide
      */
-    protected <T extends View> T findViewTraversal(@IdRes int id) {
+    protected View findViewTraversal(@IdRes int id) {
         if (id == mID) {
-            return (T) this;
+            return this;
         }
         return null;
     }
@@ -19954,9 +20062,9 @@
      * @return the view of specified tag, null if cannot be found
      * @hide
      */
-    protected <T extends View> T findViewWithTagTraversal(Object tag) {
+    protected View findViewWithTagTraversal(Object tag) {
         if (tag != null && tag.equals(mTag)) {
-            return (T) this;
+            return this;
         }
         return null;
     }
@@ -19967,10 +20075,9 @@
      * @return The first view that matches the predicate or null.
      * @hide
      */
-    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
-            View childToSkip) {
-        if (predicate.apply(this)) {
-            return (T) this;
+    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+        if (predicate.test(this)) {
+            return this;
         }
         return null;
     }
@@ -19983,7 +20090,7 @@
      * @return The view that has the given id in the hierarchy or null
      */
     @Nullable
-    public final <T extends View> T findViewById(@IdRes int id) {
+    public final View findViewById(@IdRes int id) {
         if (id < 0) {
             return null;
         }
@@ -19996,11 +20103,11 @@
      * @param accessibilityId The searched accessibility id.
      * @return The found view.
      */
-    final <T extends View> T  findViewByAccessibilityId(int accessibilityId) {
+    final View findViewByAccessibilityId(int accessibilityId) {
         if (accessibilityId < 0) {
             return null;
         }
-        T view = findViewByAccessibilityIdTraversal(accessibilityId);
+        View view = findViewByAccessibilityIdTraversal(accessibilityId);
         if (view != null) {
             return view.includeForAccessibility() ? view : null;
         }
@@ -20019,11 +20126,12 @@
      *
      * @param accessibilityId The accessibility id.
      * @return The found view.
+     *
      * @hide
      */
-    public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) {
+    public View findViewByAccessibilityIdTraversal(int accessibilityId) {
         if (getAccessibilityViewId() == accessibilityId) {
-            return (T) this;
+            return this;
         }
         return null;
     }
@@ -20035,7 +20143,7 @@
      * @param tag The tag to search for, using "tag.equals(getTag())".
      * @return The View that has the given tag in the hierarchy or null
      */
-    public final <T extends View> T findViewWithTag(Object tag) {
+    public final View findViewWithTag(Object tag) {
         if (tag == null) {
             return null;
         }
@@ -20050,7 +20158,7 @@
      * @return The first view that matches the predicate or null.
      * @hide
      */
-    public final <T extends View> T findViewByPredicate(Predicate<View> predicate) {
+    public final View findViewByPredicate(Predicate<View> predicate) {
         return findViewByPredicateTraversal(predicate, null);
     }
 
@@ -20070,11 +20178,10 @@
      * @return The first view that matches the predicate or null.
      * @hide
      */
-    public final <T extends View> T findViewByPredicateInsideOut(
-            View start, Predicate<View> predicate) {
+    public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) {
         View childToSkip = null;
         for (;;) {
-            T view = start.findViewByPredicateTraversal(predicate, childToSkip);
+            View view = start.findViewByPredicateTraversal(predicate, childToSkip);
             if (view != null || start == this) {
                 return view;
             }
@@ -24320,6 +24427,32 @@
         }
 
         /**
+         * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
+         * additional data.
+         * <p>
+         * This method only needs to be implemented if the View offers to provide additional data.
+         * </p>
+         * <p>
+         * The default implementation behaves as
+         * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, int) for
+         * the case where no accessibility delegate is set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param info The info to which to add the extra data
+         * @param extraDataKey A key specifying the type of extra data to add to the info. The
+         *                     extra data should be added to the {@link Bundle} returned by
+         *                     the info's {@link AccessibilityNodeInfo#getExtras} method.
+         * @param arguments A {@link Bundle} holding any arguments relevant for this request.
+         *
+         * @see AccessibilityNodeInfo#setExtraAvailableData
+         */
+        public void addExtraDataToAccessibilityNodeInfo(
+                View host, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+            host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments);
+        }
+
+        /**
          * Called when a child of the host View has requested sending an
          * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
          * to augment the event.
@@ -24389,20 +24522,20 @@
         }
     }
 
-    private class MatchIdPredicate implements Predicate<View> {
+    private static class MatchIdPredicate implements Predicate<View> {
         public int mId;
 
         @Override
-        public boolean apply(View view) {
+        public boolean test(View view) {
             return (view.mID == mId);
         }
     }
 
-    private class MatchLabelForPredicate implements Predicate<View> {
+    private static class MatchLabelForPredicate implements Predicate<View> {
         private int mLabeledId;
 
         @Override
-        public boolean apply(View view) {
+        public boolean test(View view) {
             return (view.mLabelForId == mLabeledId);
         }
     }
@@ -24660,7 +24793,7 @@
      * Determine if this view is rendered on a round wearable device and is the main view
      * on the screen.
      */
-    private boolean shouldDrawRoundScrollbar() {
+    boolean shouldDrawRoundScrollbar() {
         if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) {
             return false;
         }
@@ -24677,7 +24810,7 @@
             return false;
         }
 
-        getLocationOnScreen(mAttachInfo.mTmpLocation);
+        getLocationInWindow(mAttachInfo.mTmpLocation);
         return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft()
                 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop();
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b11b3d7..fd3ff82 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -57,14 +57,15 @@
 import android.view.animation.Transformation;
 
 import com.android.internal.R;
-import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 /**
  * <p>
@@ -140,6 +141,8 @@
     // The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
     // that is or contains a default-focus view.
     private View mDefaultFocus;
+    // The last child of this ViewGroup which held focus within the current cluster
+    private View mFocusedInCluster;
 
     /**
      * A Transformation used when drawing children, to
@@ -723,7 +726,7 @@
         if (mFocused != null) {
             mFocused.unFocus(this);
             mFocused = null;
-            mDefaultFocus = null;
+            mFocusedInCluster = null;
         }
         super.handleFocusGainInternal(direction, previouslyFocusedRect);
     }
@@ -753,14 +756,9 @@
         }
     }
 
-    /**
-     * Sets the specified child view as the default focus for this view and all its ancestors.
-     * If the view is inside a keyboard navigation cluster, stops at the root of the cluster since
-     * the cluster forms a separate keyboard navigation hierarchy from the default focus point of
-     * view.
-     */
     void setDefaultFocus(View child) {
-        if (child.isKeyboardNavigationCluster()) {
+        // Stop at any higher view which is explicitly focused-by-default
+        if (mDefaultFocus != null && mDefaultFocus.isFocusedByDefault()) {
             return;
         }
 
@@ -772,10 +770,56 @@
     }
 
     /**
-     * Destroys the default focus chain.
+     * Clears the default-focus chain from {@param child} up to the first parent which has another
+     * default-focusable branch below it or until there is no default-focus chain.
+     *
+     * @param child
      */
-    void cleanDefaultFocus(View child) {
-        if (mDefaultFocus != child) {
+    void clearDefaultFocus(View child) {
+        // Stop at any higher view which is explicitly focused-by-default
+        if (mDefaultFocus != child && mDefaultFocus != null
+                && mDefaultFocus.isFocusedByDefault()) {
+            return;
+        }
+
+        mDefaultFocus = null;
+
+        // Search child siblings for default focusables.
+        for (int i = 0; i < mChildrenCount; ++i) {
+            View sibling = mChildren[i];
+            if (sibling.isFocusedByDefault()) {
+                mDefaultFocus = sibling;
+                return;
+            } else if (mDefaultFocus == null && sibling.hasDefaultFocus()) {
+                mDefaultFocus = sibling;
+            }
+        }
+
+        if (mParent instanceof ViewGroup) {
+            ((ViewGroup) mParent).clearDefaultFocus(this);
+        }
+    }
+
+    @Override
+    boolean hasDefaultFocus() {
+        return mDefaultFocus != null || super.hasDefaultFocus();
+    }
+
+    void setFocusInCluster(View child) {
+        // Stop at the root of the cluster
+        if (child.isKeyboardNavigationCluster()) {
+            return;
+        }
+
+        mFocusedInCluster = child;
+
+        if (mParent instanceof ViewGroup) {
+            ((ViewGroup) mParent).setFocusInCluster(this);
+        }
+    }
+
+    void clearFocusInCluster(View child) {
+        if (mFocusedInCluster != child) {
             return;
         }
 
@@ -783,19 +827,14 @@
             return;
         }
 
-        mDefaultFocus = null;
+        mFocusedInCluster = null;
 
         if (mParent instanceof ViewGroup) {
-            ((ViewGroup) mParent).cleanDefaultFocus(this);
+            ((ViewGroup) mParent).clearFocusInCluster(this);
         }
     }
 
     @Override
-    boolean hasDefaultFocus() {
-        return mDefaultFocus != null || super.hasDefaultFocus();
-    }
-
-    @Override
     public void focusableViewAvailable(View v) {
         if (mParent != null
                 // shortcut: don't report a new focusable view if we block our descendants from
@@ -1106,14 +1145,15 @@
         return null;
     }
 
-    /** @hide Overriding hidden method */
     @Override
-    public boolean hasFocusable(boolean allowAutoFocus) {
+    boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
         if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
             return false;
         }
 
-        // TODO This should probably be super.hasFocusable, but that would change behavior
+        // TODO This should probably be super.hasFocusable, but that would change behavior.
+        // The below is a much simpler check than we do in the superclass implementation,
+        // but it's been this way for a long time and other code likely relies on it.
         if ((allowAutoFocus ? getFocusable() != NOT_FOCUSABLE : getFocusable() == FOCUSABLE)
                 && isFocusable()) {
             return true;
@@ -1126,7 +1166,11 @@
 
             for (int i = 0; i < count; i++) {
                 final View child = children[i];
-                if (child.hasFocusable(allowAutoFocus)) {
+
+                // In case the subclass has overridden has[Explicit]Focusable, dispatch
+                // to the expected one for each child even though we share logic here.
+                if ((dispatchExplicit && child.hasExplicitFocusable())
+                        || (!dispatchExplicit && child.hasFocusable())) {
                     return true;
                 }
             }
@@ -1140,31 +1184,42 @@
         final int focusableCount = views.size();
 
         final int descendantFocusability = getDescendantFocusability();
+        final boolean focusSelf = (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen());
 
-        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
-            if (shouldBlockFocusForTouchscreen()) {
-                focusableMode |= FOCUSABLES_TOUCH_MODE;
+        if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
+            if (focusSelf) {
+                super.addFocusables(views, direction, focusableMode);
             }
-
-            final int count = mChildrenCount;
-            final View[] children = mChildren;
-
-            for (int i = 0; i < count; i++) {
-                final View child = children[i];
-                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
-                    child.addFocusables(views, direction, focusableMode);
-                }
-            }
+            return;
         }
 
-        // we add ourselves (if focusable) in all cases except for when we are
-        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
+        if (shouldBlockFocusForTouchscreen()) {
+            focusableMode |= FOCUSABLES_TOUCH_MODE;
+        }
+
+        if ((descendantFocusability == FOCUS_BEFORE_DESCENDANTS) && focusSelf) {
+            super.addFocusables(views, direction, focusableMode);
+        }
+
+        int count = 0;
+        final View[] children = new View[mChildrenCount];
+        for (int i = 0; i < mChildrenCount; ++i) {
+            View child = mChildren[i];
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+                children[count++] = child;
+            }
+        }
+        Arrays.sort(children, 0, count, FocusFinder.getFocusComparator(this, false));
+        for (int i = 0; i < count; ++i) {
+            children[i].addFocusables(views, direction, focusableMode);
+        }
+
+        // When set to FOCUS_AFTER_DESCENDANTS, we only add ourselves if
+        // there aren't any focusable descendants.  this is
         // to avoid the focus search finding layouts when a more precise search
         // among the focusable children would be more interesting.
-        if ((descendantFocusability != FOCUS_AFTER_DESCENDANTS
-                // No focusable descendants
-                || (focusableCount == views.size())) &&
-                (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())) {
+        if ((descendantFocusability == FOCUS_AFTER_DESCENDANTS) && focusSelf
+                && focusableCount == views.size()) {
             super.addFocusables(views, direction, focusableMode);
         }
     }
@@ -3098,14 +3153,28 @@
     }
 
     @Override
-    public boolean restoreDefaultFocus(@FocusDirection int direction) {
-        if (mDefaultFocus != null && !mDefaultFocus.isKeyboardNavigationCluster()
+    public boolean restoreDefaultFocus() {
+        if (mDefaultFocus != null
                 && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
                 && (mDefaultFocus.mViewFlags & VISIBILITY_MASK) == VISIBLE
-                && mDefaultFocus.restoreDefaultFocus(direction)) {
+                && mDefaultFocus.restoreDefaultFocus()) {
             return true;
         }
-        return super.restoreDefaultFocus(direction);
+        return super.restoreDefaultFocus();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
+        if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster()
+                && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
+                && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
+                && mFocusedInCluster.restoreFocusInCluster(direction)) {
+            return true;
+        }
+        return super.restoreFocusInCluster(direction);
     }
 
     /**
@@ -4208,9 +4277,9 @@
      * {@hide}
      */
     @Override
-    protected <T extends View> T findViewTraversal(@IdRes int id) {
+    protected View findViewTraversal(@IdRes int id) {
         if (id == mID) {
-            return (T) this;
+            return this;
         }
 
         final View[] where = mChildren;
@@ -4223,7 +4292,7 @@
                 v = v.findViewById(id);
 
                 if (v != null) {
-                    return (T) v;
+                    return v;
                 }
             }
         }
@@ -4235,9 +4304,9 @@
      * {@hide}
      */
     @Override
-    protected <T extends View> T findViewWithTagTraversal(Object tag) {
+    protected View findViewWithTagTraversal(Object tag) {
         if (tag != null && tag.equals(mTag)) {
-            return (T) this;
+            return this;
         }
 
         final View[] where = mChildren;
@@ -4250,7 +4319,7 @@
                 v = v.findViewWithTag(tag);
 
                 if (v != null) {
-                    return (T) v;
+                    return v;
                 }
             }
         }
@@ -4262,10 +4331,9 @@
      * {@hide}
      */
     @Override
-    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
-            View childToSkip) {
-        if (predicate.apply(this)) {
-            return (T) this;
+    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+        if (predicate.test(this)) {
+            return this;
         }
 
         final View[] where = mChildren;
@@ -4278,7 +4346,7 @@
                 v = v.findViewByPredicate(predicate);
 
                 if (v != null) {
-                    return (T) v;
+                    return v;
                 }
             }
         }
@@ -4988,8 +5056,8 @@
             view.unFocus(null);
             clearChildFocus = true;
         }
-        if (view == mDefaultFocus) {
-            mDefaultFocus = null;
+        if (view == mFocusedInCluster) {
+            clearFocusInCluster(view);
         }
 
         view.clearAccessibilityFocus();
@@ -5012,6 +5080,9 @@
 
         removeFromArray(index);
 
+        if (view == mDefaultFocus) {
+            clearDefaultFocus(view);
+        }
         if (clearChildFocus) {
             clearChildFocus(view);
             if (!rootViewRequestFocus()) {
@@ -5087,6 +5158,7 @@
         final View focused = mFocused;
         final boolean detach = mAttachInfo != null;
         boolean clearChildFocus = false;
+        View clearDefaultFocus = null;
 
         final View[] children = mChildren;
 
@@ -5102,7 +5174,10 @@
                 clearChildFocus = true;
             }
             if (view == mDefaultFocus) {
-                mDefaultFocus = null;
+                clearDefaultFocus = view;
+            }
+            if (view == mFocusedInCluster) {
+                clearFocusInCluster(view);
             }
 
             view.clearAccessibilityFocus();
@@ -5128,6 +5203,9 @@
 
         removeFromArray(start, count);
 
+        if (clearDefaultFocus != null) {
+            clearDefaultFocus(clearDefaultFocus);
+        }
         if (clearChildFocus) {
             clearChildFocus(focused);
             if (!rootViewRequestFocus()) {
@@ -5177,7 +5255,6 @@
         boolean clearChildFocus = false;
 
         needGlobalAttributesUpdate(false);
-        mDefaultFocus = null;
 
         for (int i = count - 1; i >= 0; i--) {
             final View view = children[i];
@@ -5213,6 +5290,9 @@
             children[i] = null;
         }
 
+        if (mDefaultFocus != null) {
+            clearDefaultFocus(mDefaultFocus);
+        }
         if (clearChildFocus) {
             clearChildFocus(focused);
             if (!rootViewRequestFocus()) {
@@ -5250,7 +5330,10 @@
             child.clearFocus();
         }
         if (child == mDefaultFocus) {
-            mDefaultFocus = null;
+            clearDefaultFocus(child);
+        }
+        if (child == mFocusedInCluster) {
+            clearFocusInCluster(child);
         }
 
         child.clearAccessibilityFocus();
@@ -6235,6 +6318,12 @@
             Log.d(VIEW_LOG_TAG, output);
             mDefaultFocus.debug(depth + 1);
         }
+        if (mFocusedInCluster != null) {
+            output = debugIndent(depth);
+            output += "mFocusedInCluster";
+            Log.d(VIEW_LOG_TAG, output);
+            mFocusedInCluster.debug(depth + 1);
+        }
         if (mChildrenCount != 0) {
             output = debugIndent(depth);
             output += "{";
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9bfc260..bdc3e7f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2162,7 +2162,7 @@
                     + mView.hasFocus());
             if (mView != null) {
                 if (!mView.hasFocus()) {
-                    mView.restoreDefaultFocus(View.FOCUS_FORWARD);
+                    mView.restoreDefaultFocus();
                     if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view="
                             + mView.findFocus());
                 } else {
@@ -4441,7 +4441,14 @@
                     ? focused.keyboardNavigationClusterSearch(null, direction)
                     : keyboardNavigationClusterSearch(null, direction);
 
-            if (cluster != null && cluster.restoreDefaultFocus(View.FOCUS_DOWN)) {
+            // Since requestFocus only takes "real" focus directions (and therefore also
+            // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
+            int realDirection = direction;
+            if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
+                realDirection = View.FOCUS_DOWN;
+            }
+
+            if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
                 return true;
             }
 
@@ -4472,9 +4479,9 @@
                 }
             }
 
-            // If the Control modifier is held, try to interpret the key as a shortcut.
+            // If a modifier is held, try to interpret the key as a shortcut.
             if (event.getAction() == KeyEvent.ACTION_DOWN
-                    && event.isCtrlPressed()
+                    && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
                     && event.getRepeatCount() == 0
                     && !KeyEvent.isModifierKey(event.getKeyCode())
                     && groupNavigationDirection == 0) {
@@ -7492,13 +7499,13 @@
         public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
                 Region interactiveRegion, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
-                            interrogatingTid, spec);
+                            interrogatingTid, spec, args);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 5bae594..cc19539 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -22,7 +22,6 @@
 import android.view.autofill.AutoFillId;
 import android.view.autofill.AutoFillType;
 import android.view.autofill.AutoFillValue;
-import android.view.autofill.VirtualViewDelegate;
 
 /**
  * Container for storing additional per-view data generated by {@link View#onProvideStructure
@@ -272,12 +271,11 @@
 
     /**
      * Like {@link #newChild(int)}, but providing a {@code virtualId} to the child so it can be
-     * auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     * auto-filled by {@link View#autoFillVirtual(int, AutoFillValue)}.
      *
      * @param index child index
-     * @param virtualId child's id as defined by {@link VirtualViewDelegate#autoFill(int,
-     * AutoFillValue)}.
-     * @param flags currently either {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}.
+     * @param virtualId id identifying the virtual child inside the custom view.
+     * @param flags currently {@code 0}.
      */
     // TODO(b/33197203, b/33802548): add CTS/unit test
     public abstract ViewStructure newChild(int index, int virtualId, int flags);
@@ -294,12 +292,11 @@
 
     /**
      * Like {@link #asyncNewChild(int)}, but providing a {@code virtualId} to the child so it can be
-     * auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     * auto-filled by {@link View#autoFillVirtual(int, AutoFillValue)}.
      *
      * @param index child index
-     * @param virtualId child's id as defined by {@link VirtualViewDelegate#autoFill(int,
-     * AutoFillValue)}.
-     * @param flags currently either {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}.
+     * @param virtualId id identifying the virtual child inside the custom view.
+     * @param flags currently {@code 0}.
      */
     // TODO(b/33197203, b/33802548): add CTS/unit test
     public abstract ViewStructure asyncNewChild(int index, int virtualId, int flags);
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index db2ea48..143c49a 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -554,7 +554,7 @@
     // Layer of indirection included to break dependency chain for testing
     public static class AccessibilityNodeRefresher {
         public boolean refreshNode(AccessibilityNodeInfo info, boolean bypassCache) {
-            return info.refresh(bypassCache);
+            return info.refresh(null, bypassCache);
         }
     }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 1543597..828583c 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -159,7 +159,7 @@
     public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) {
         return findAccessibilityNodeInfoByAccessibilityId(connectionId,
                 AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
-                false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+                false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS, null);
     }
 
     /**
@@ -259,7 +259,7 @@
      */
     public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
             int accessibilityWindowId, long accessibilityNodeId, boolean bypassCache,
-            int prefetchFlags) {
+            int prefetchFlags, Bundle arguments) {
         if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0
                 && (prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) == 0) {
             throw new IllegalArgumentException("FLAG_PREFETCH_SIBLINGS"
@@ -285,9 +285,8 @@
                 final long identityToken = Binder.clearCallingIdentity();
                 final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
                         accessibilityWindowId, accessibilityNodeId, interactionId, this,
-                        prefetchFlags, Thread.currentThread().getId());
+                        prefetchFlags, Thread.currentThread().getId(), arguments);
                 Binder.restoreCallingIdentity(identityToken);
-                // If the scale is zero the call has failed.
                 if (success) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 1ef0d17..45302b6 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -779,6 +779,49 @@
         }
     }
 
+    /**
+     * Notifies that the accessibility button in the system's navigation area has been clicked
+     *
+     * @hide
+     */
+    public void notifyAccessibilityButtonClicked() {
+        final IAccessibilityManager service;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return;
+            }
+        }
+        try {
+            service.notifyAccessibilityButtonClicked();
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error while dispatching accessibility button click", re);
+        }
+    }
+
+    /**
+     * Notifies that the availability of the accessibility button in the system's navigation area
+     * has changed.
+     *
+     * @param available {@code true} if the accessibility button is available within the system
+     *                  navigation area, {@code false} otherwise
+     * @hide
+     */
+    public void notifyAccessibilityButtonAvailabilityChanged(boolean available) {
+        final IAccessibilityManager service;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return;
+            }
+        }
+        try {
+            service.notifyAccessibilityButtonAvailabilityChanged(available);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error while dispatching accessibility button availability change", re);
+        }
+    }
+
     private IAccessibilityManager getServiceLocked() {
         if (mService == null) {
             tryConnectToServiceLocked(null);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 56d45b0..b0a11cd 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -16,6 +16,8 @@
 
 package android.view.accessibility;
 
+import static java.util.Collections.EMPTY_LIST;
+
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.Nullable;
@@ -517,6 +519,46 @@
      */
     public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
 
+    /**
+     * Key used to request and locate extra data for text character location. This key requests that
+     * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with
+     * {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by this request are two
+     * integers: {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and
+     * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid
+     * inside the CharSequence returned by {@link #getText()}, and the length must be positive.
+     * <p>
+     * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this
+     * string as a key for {@link Bundle#getParcelableArray(String)}. The
+     * {@link android.graphics.RectF} will be null for characters that either do not exist or are
+     * off the screen.
+     *
+     * {@see #refreshWithExtraData(String, Bundle)}
+     */
+    public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY =
+            "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+
+    /**
+     * Integer argument specifying the start index of the requested text location data. Must be
+     * valid inside the CharSequence returned by {@link #getText()}.
+     *
+     * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
+     */
+    public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX =
+            "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+
+    /**
+     * Integer argument specifying the end index of the requested text location data. Must be
+     * positive.
+     *
+     * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
+     */
+    public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH =
+            "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+
+    /** @hide */
+    public static final String EXTRA_DATA_REQUESTED_KEY =
+            "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested";
+
     // Boolean attributes.
 
     private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
@@ -651,6 +693,7 @@
     private CharSequence mError;
     private CharSequence mContentDescription;
     private String mViewIdResourceName;
+    private ArrayList<String> mExtraDataKeys;
 
     private LongArray mChildNodeIds;
     private ArrayList<AccessibilityAction> mActions;
@@ -786,14 +829,14 @@
      *
      * @hide
      */
-    public boolean refresh(boolean bypassCache) {
+    public boolean refresh(Bundle arguments, boolean bypassCache) {
         enforceSealed();
         if (!canPerformRequestOverConnection(mSourceNodeId)) {
             return false;
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
-                mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0);
+                mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0, arguments);
         if (refreshedInfo == null) {
             return false;
         }
@@ -804,15 +847,33 @@
 
     /**
      * Refreshes this info with the latest state of the view it represents.
-     * <p>
-     * <strong>Note:</strong> If this method returns false this info is obsolete
-     * since it represents a view that is no longer in the view tree and should
-     * be recycled.
-     * </p>
-     * @return Whether the refresh succeeded.
+     *
+     * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
+     * by this node is no longer in the view tree (and thus this node is obsolete and should be
+     * recycled).
      */
     public boolean refresh() {
-        return refresh(true);
+        return refresh(null, true);
+    }
+
+    /**
+     * Refreshes this info with the latest state of the view it represents, and request new
+     * data be added by the View.
+     *
+     * @param extraDataKey A bitmask of the extra data requested. Data that must be requested
+     *                     with this mechanism is generally expensive to retrieve, so should only be
+     *                     requested when needed. See
+     *                     {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
+     *                     {@link #getAvailableExtraData()}.
+     * @param args A bundle of arguments for the request. These depend on the particular request.
+     *
+     * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
+     * by this node is no longer in the view tree (and thus this node is obsolete and should be
+     * recycled).
+     */
+    public boolean refreshWithExtraData(String extraDataKey, Bundle args) {
+        args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey);
+        return refresh(args, true);
     }
 
     /**
@@ -872,7 +933,7 @@
         final long childId = mChildNodeIds.get(index);
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
-                childId, false, FLAG_PREFETCH_DESCENDANTS);
+                childId, false, FLAG_PREFETCH_DESCENDANTS, null);
     }
 
     /**
@@ -1263,6 +1324,45 @@
     }
 
     /**
+     * Get the extra data available for this node.
+     * <p>
+     * Some data that is useful for some accessibility services is expensive to compute, and would
+     * place undue overhead on apps to compute all the time. That data can be requested with
+     * {@link #refreshWithExtraData(String, Bundle)}.
+     *
+     * @return An unmodifiable list of keys corresponding to extra data that can be requested.
+     * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
+     */
+    public List<String> getAvailableExtraData() {
+        if (mExtraDataKeys != null) {
+            return Collections.unmodifiableList(mExtraDataKeys);
+        } else {
+            return EMPTY_LIST;
+        }
+    }
+
+    /**
+     * Set the extra data available for this node.
+     * <p>
+     * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that
+     * it will populate the node's extras with corresponding pieces of information in
+     * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}.
+     * <p>
+     * <strong>Note:</strong> Cannot be called from an
+     * {@link android.accessibilityservice.AccessibilityService}.
+     * This class is made immutable before being delivered to an AccessibilityService.
+     *
+     * @param extraDataKeys A list of types of extra data that are available.
+     * @see #getAvailableExtraData()
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setAvailableExtraData(List<String> extraDataKeys) {
+        enforceNotSealed();
+        mExtraDataKeys = new ArrayList<>(extraDataKeys);
+    }
+
+    /**
      * Sets the maximum text length, or -1 for no limit.
      * <p>
      * Typically used to indicate that an editable text field has a limit on
@@ -2658,6 +2758,14 @@
     }
 
     /**
+     * Check if a node has an extras bundle
+     * @hide
+     */
+    public boolean hasExtras() {
+        return mExtras != null;
+    }
+
+    /**
      * Gets the value of a boolean property.
      *
      * @param property The property.
@@ -2955,6 +3063,12 @@
         parcel.writeInt(mInputType);
         parcel.writeInt(mLiveRegion);
         parcel.writeInt(mDrawingOrderInParent);
+        if (mExtraDataKeys != null) {
+            parcel.writeInt(1);
+            parcel.writeStringList(mExtraDataKeys);
+        } else {
+            parcel.writeInt(0);
+        }
 
         if (mExtras != null) {
             parcel.writeInt(1);
@@ -3054,6 +3168,8 @@
         mInputType = other.mInputType;
         mLiveRegion = other.mLiveRegion;
         mDrawingOrderInParent = other.mDrawingOrderInParent;
+        mExtraDataKeys = other.mExtraDataKeys;
+
         if (other.mExtras != null) {
             mExtras = new Bundle(other.mExtras);
         } else {
@@ -3137,6 +3253,12 @@
         mDrawingOrderInParent = parcel.readInt();
 
         if (parcel.readInt() == 1) {
+            mExtraDataKeys = parcel.createStringArrayList();
+        } else {
+            mExtraDataKeys = null;
+        }
+
+        if (parcel.readInt() == 1) {
             mExtras = parcel.readBundle();
         } else {
             mExtras = null;
@@ -3455,7 +3577,7 @@
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
                 mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
-                        | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+                        | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
     }
 
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index abcbb70..722b659 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -102,6 +102,27 @@
     }
 
     /**
+     * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
+     * additional data.
+     * <p>
+     * This method only needs to be implemented if a virtual view offers to provide additional
+     * data.
+     * </p>
+     *
+     * @param virtualViewId The virtual view id used to create the node
+     * @param info The info to which to add the extra data
+     * @param extraDataKey A key specifying the type of extra data to add to the info. The
+     *                     extra data should be added to the {@link Bundle} returned by
+     *                     the info's {@link AccessibilityNodeInfo#getExtras} method.
+     * @param arguments A {@link Bundle} holding any arguments relevant for this request.
+     *
+     * @see AccessibilityNodeInfo#setExtraAvailableData
+     */
+    public void addExtraDataToAccessibilityNodeInfo(
+            int virtualViewId, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+    }
+
+    /**
      * Performs an accessibility action on a virtual view, i.e. a descendant of the
      * host View, with the given <code>virtualViewId</code> or the host View itself
      * if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 3287298..c390406 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -183,7 +183,7 @@
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
                 mId, AccessibilityNodeInfo.ROOT_NODE_ID,
-                true, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+                true, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS, null);
     }
 
     /**
@@ -209,7 +209,7 @@
 
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mParentId, mAnchorId, true, 0);
+                mParentId, mAnchorId, true, 0, null);
     }
 
     /**
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index cecc4af..4c0fdfd 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -33,7 +33,8 @@
 
     void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, in Region bounds,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
-        int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
+        int interrogatingPid, long interrogatingTid, in MagnificationSpec spec,
+        in Bundle arguments);
 
     void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId,
         in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 136bbbe..8fde47a 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -59,6 +59,10 @@
 
     IBinder getWindowToken(int windowId, int userId);
 
+    void notifyAccessibilityButtonClicked();
+
+    void notifyAccessibilityButtonAvailabilityChanged(boolean available);
+
     // Requires WRITE_SECURE_SETTINGS
     void performAccessibilityShortcut();
 
diff --git a/core/java/android/view/autofill/AutoFillId.java b/core/java/android/view/autofill/AutoFillId.java
index 3dbf5a8..38dc404 100644
--- a/core/java/android/view/autofill/AutoFillId.java
+++ b/core/java/android/view/autofill/AutoFillId.java
@@ -93,11 +93,11 @@
     public String toString() {
         if (!DEBUG) return super.toString();
 
-        final StringBuilder builder = new StringBuilder("FieldId [viewId=").append(mViewId);
+        final StringBuilder builder = new StringBuilder().append(mViewId);
         if (mVirtual) {
-            builder.append(", virtualId=").append(mVirtualId);
+            builder.append(":").append(mVirtualId);
         }
-        return builder.append(']').toString();
+        return builder.toString();
     }
 
     @Override
diff --git a/core/java/android/view/autofill/AutoFillManager.java b/core/java/android/view/autofill/AutoFillManager.java
index f2f522d..58607ba 100644
--- a/core/java/android/view/autofill/AutoFillManager.java
+++ b/core/java/android/view/autofill/AutoFillManager.java
@@ -16,9 +16,12 @@
 
 package android.view.autofill;
 
+import static android.view.autofill.Helper.VERBOSE;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.service.autofill.IAutoFillManagerService;
 import android.util.Log;
@@ -28,95 +31,181 @@
  * App entry point to the AutoFill Framework.
  */
 // TODO(b/33197203): improve this javadoc
+//TODO(b/33197203): restrict manager calls to activity
 public final class AutoFillManager {
 
     private static final String TAG = "AutoFillManager";
-    private static final boolean DEBUG = true; // TODO(b/33197203): change to false once stable
 
-    /**
-     * Flag used to show the auto-fill UI affordance for a view.
-     */
-    public static final int FLAG_UPDATE_UI_SHOW = 0x1;
-
-    /**
-     * Flag used to hide the auto-fill UI affordance for a view.
-     */
-    public static final int FLAG_UPDATE_UI_HIDE = 0x2;
+    /** @hide */ public static final int FLAG_START_SESSION = 0x1;
+    /** @hide */ public static final int FLAG_FOCUS_GAINED = 0x2;
+    /** @hide */ public static final int FLAG_FOCUS_LOST = 0x4;
+    /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x8;
 
     private final IAutoFillManagerService mService;
+    private final Context mContext;
+
+    private AutoFillSession mSession;
 
     /**
      * @hide
      */
-    public AutoFillManager(@SuppressWarnings("unused") Context context,
-            IAutoFillManagerService service) {
+    public AutoFillManager(Context context, IAutoFillManagerService service) {
+        mContext = context;
         mService = service;
     }
 
     /**
-     * Updates the auto-fill bar for a given {@link View}.
+     * Called to indicate the focus on an auto-fillable {@link View} changed.
      *
-     * <b>Typically called twice, with different flags ({@link #FLAG_UPDATE_UI_SHOW} and
-     * {@link #FLAG_UPDATE_UI_HIDE} respectively), as the user "entered" and "exited" a view.
-     *
-     * @param view view to be updated.
-     * @param flags either {@link #FLAG_UPDATE_UI_SHOW} or
-     * {@link #FLAG_UPDATE_UI_HIDE}.
+     * @param view view whose focus changed.
+     * @param gainFocus whether focus was gained or lost.
      */
-    public void updateAutoFillInput(View view, int flags) {
+    public void focusChanged(View view, boolean gainFocus) {
+        if (mSession == null) {
+            // Starts new session.
+            final Rect bounds = new Rect();
+            view.getBoundsOnScreen(bounds);
+            final AutoFillId id = getAutoFillId(view);
+            final AutoFillValue value = view.getAutoFillValue();
+            startSession(id, bounds, value);
+            return;
+        }
+
+        if (!mSession.isEnabled()) {
+            // Auto-fill is disabled for this session.
+            return;
+        }
+
+        // Update focus on existing session.
         final Rect bounds = new Rect();
         view.getBoundsOnScreen(bounds);
-
-        requestAutoFill(getAutoFillId(view), bounds, flags);
-    }
-
-    /**
-     * Updates the auto-fill bar for a virtual child of a given {@link View}.
-     *
-     * <b>Typically called twice, with different flags ({@link #FLAG_UPDATE_UI_SHOW} and
-     * {@link #FLAG_UPDATE_UI_HIDE} respectively), as the user "entered" and "exited" a view.
-     *
-     * @param parent parent view.
-     * @param childId id identifying the virtual child inside the parent view.
-     * @param bounds absolute boundaries of the child in the window (could be {@code null} when
-     * flag is {@link #FLAG_UPDATE_UI_HIDE}.
-     * @param flags either {@link #FLAG_UPDATE_UI_SHOW} or
-     * {@link #FLAG_UPDATE_UI_HIDE}.
-     */
-    public void updateAutoFillInput(View parent, int childId, @Nullable Rect bounds,
-            int flags) {
-        requestAutoFill(new AutoFillId(parent.getAccessibilityViewId(), childId), bounds, flags);
-    }
-
-    /**
-     * Notifies the framework that the value of a view changed.
-     * @param view view whose value was updated
-     * @param value new value.
-     */
-    public void onValueChanged(View view, AutoFillValue value) {
-        // TODO(b/33197203): optimize it by not calling service when the view does not belong to
-        // the session.
         final AutoFillId id = getAutoFillId(view);
-        if (DEBUG) Log.v(TAG, "onValueChanged(): id=" + id + ", value=" + value);
+        final AutoFillValue value = view.getAutoFillValue();
+        updateSession(id, bounds, value, gainFocus ? FLAG_FOCUS_GAINED : FLAG_FOCUS_LOST);
+    }
+
+    /**
+     * Called to indicate the focus on an auto-fillable virtual {@link View} changed.
+     *
+     * @param parent parent view whose focus changed.
+     * @param childId id identifying the virtual child inside the parent view.
+     * @param bounds child boundaries, relative to the top window.
+     * @param gainFocus whether focus was gained or lost.
+     */
+    public void virtualFocusChanged(View parent, int childId, Rect bounds, boolean gainFocus) {
+        if (mSession == null) {
+            // Starts new session.
+            final AutoFillId id = getAutoFillId(parent, childId);
+            startSession(id, bounds, null);
+            return;
+        }
+
+        if (!mSession.isEnabled()) {
+            // Auto-fill is disabled for this session.
+            return;
+        }
+
+        // Update focus on existing session.
+        final AutoFillId id = getAutoFillId(parent, childId);
+        updateSession(id, bounds, null, gainFocus ? FLAG_FOCUS_GAINED : FLAG_FOCUS_LOST);
+    }
+
+    /**
+     * Called to indicate the value of an auto-fillable {@link View} changed.
+     *
+     * @param view view whose focus changed.
+     */
+    public void valueChanged(View view) {
+        if (mSession == null) return;
+
+        final AutoFillId id = getAutoFillId(view);
+        final AutoFillValue value = view.getAutoFillValue();
+        updateSession(id, null, value, FLAG_VALUE_CHANGED);
+    }
+
+
+    /**
+     * Called to indicate the value of an auto-fillable virtual {@link View} changed.
+     *
+     * @param parent parent view whose value changed.
+     * @param childId id identifying the virtual child inside the parent view.
+     * @param value new value of the child.
+     */
+    public void virtualValueChanged(View parent, int childId, AutoFillValue value) {
+        if (mSession == null) return;
+
+        final AutoFillId id = getAutoFillId(parent, childId);
+        updateSession(id, null, value, FLAG_VALUE_CHANGED);
+    }
+
+    /**
+     * Called to indicate the current auto-fill context should be reset.
+     *
+     * <p>For example, when a virtual view is rendering an {@code HTML} page with a form, it should
+     * call this method after the form is submitted and another page is rendered.
+     */
+    public void reset() {
+        if (mSession == null) return;
+
+        final IBinder activityToken = mSession.mToken.get();
+        if (activityToken == null) {
+            Log.wtf(TAG, "finishSession(): token already GC'ed");
+            return;
+        }
         try {
-            mService.onValueChanged(id, value);
+            mService.finishSession(activityToken);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } finally {
+            mSession = null;
         }
     }
 
+    /**
+     * Gets the current session, if any.
+     *
+     * @hide
+     */
+    @Nullable
+    public AutoFillSession getSession() {
+        return mSession;
+    }
+
     private AutoFillId getAutoFillId(View view) {
         return new AutoFillId(view.getAccessibilityViewId());
     }
 
-    private void requestAutoFill(AutoFillId id, Rect bounds, int flags) {
-        // TODO(b/33197203): optimize it by not calling service when the view does not belong to
-        // the session.
-        if (DEBUG) {
-            Log.v(TAG, "requestAutoFill(): id=" + id + ", bounds=" + bounds + ", flags=" + flags);
+    private AutoFillId getAutoFillId(View parent, int childId) {
+        return new AutoFillId(parent.getAccessibilityViewId(), childId);
+    }
+
+    private void startSession(AutoFillId id, Rect bounds, AutoFillValue value) {
+        if (VERBOSE) {
+            Log.v(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value);
+        }
+
+        final IBinder activityToken = mContext.getActivityToken();
+        mSession = new AutoFillSession(this, activityToken);
+        final IBinder appCallback = mSession.getCallback().asBinder();
+        try {
+            mService.startSession(activityToken, appCallback, id, bounds, value);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private void updateSession(AutoFillId id, Rect bounds, AutoFillValue value, int flags) {
+        if (VERBOSE) {
+            Log.v(TAG, "updateSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+                    + ", flags=" + flags);
+        }
+
+        final IBinder activityToken = mSession.mToken.get();
+        if (activityToken == null) {
+            return;
         }
         try {
-            mService.requestAutoFill(id, bounds, flags);
+            mService.updateSession(activityToken, id, bounds, value, flags);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/autofill/AutoFillSession.java b/core/java/android/view/autofill/AutoFillSession.java
index eec7a82..64df62f 100644
--- a/core/java/android/view/autofill/AutoFillSession.java
+++ b/core/java/android/view/autofill/AutoFillSession.java
@@ -19,13 +19,13 @@
 import static android.view.autofill.Helper.DEBUG;
 
 import android.app.Activity;
-import android.os.RemoteException;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.IBinder;
 import android.service.autofill.IAutoFillAppCallback;
 import android.util.Log;
 import android.view.View;
 
-import com.android.internal.annotations.GuardedBy;
-
 import java.lang.ref.WeakReference;
 
 /**
@@ -38,8 +38,16 @@
     private static final String TAG = "AutoFillSession";
 
     private final IAutoFillAppCallback mCallback = new IAutoFillAppCallback.Stub() {
+
         @Override
-        public void autoFill(Dataset dataset) throws RemoteException {
+        public void enableSession() {
+            if (DEBUG) Log.d(TAG, "enableSession()");
+
+            mEnabled = true;
+        }
+
+        @Override
+        public void autoFill(Dataset dataset) {
             final Activity activity = mActivity.get();
             if (activity == null) {
                 if (DEBUG) Log.d(TAG, "autoFill(): activity already GCed");
@@ -49,12 +57,10 @@
             // dataset.extras to service
             activity.runOnUiThread(() -> {
                 final View root = activity.getWindow().getDecorView().getRootView();
-                for (DatasetField field : dataset.getFields()) {
-                    final AutoFillId id = field.getId();
-                    if (id == null) {
-                        Log.w(TAG, "autoFill(): null id on " + field);
-                        continue;
-                    }
+                final int itemCount = dataset.getFieldIds().size();
+                for (int i = 0; i < itemCount; i++) {
+                    final AutoFillId id = dataset.getFieldIds().get(i);
+                    final AutoFillValue value = dataset.getFieldValues().get(i);
                     final int viewId = id.getViewId();
                     final View view = root.findViewByAccessibilityIdTraversal(viewId);
                     if (view == null) {
@@ -62,57 +68,84 @@
                         continue;
                     }
 
-                    // TODO(b/33197203): handle protected value (like credit card)
                     if (id.isVirtual()) {
-                        // Delegate virtual fields.
-                        setAutoFillDelegateCallback();
-                        final VirtualViewDelegate delegate = view
-                                .getAutoFillVirtualViewDelegate(
-                                        mAutoFillDelegateCallback);
-                        if (delegate == null) {
-                            Log.w(TAG, "autoFill(): cannot fill virtual " + id
-                                    + "; no VirtualViewDelegate for view "
-                                    + view.getClass());
-                            continue;
-                        }
-                        if (DEBUG) {
-                            Log.d(TAG, "autoFill(): delegating " + id
-                                    + " to VirtualViewDelegate  " + delegate);
-                        }
-                        delegate.autoFill(id.getVirtualChildId(), field.getValue());
+                        view.autoFillVirtual(id.getVirtualChildId(), value);
                     } else {
-                        // Handle non-virtual fields itself.
-                        view.autoFill(field.getValue());
+                        view.autoFill(value);
                     }
                 }
             });
         }
+
+        @Override
+        public void startIntentSender(IntentSender intent, Intent fillInIntent) {
+            final Activity activity = mActivity.get();
+            if (activity != null) {
+                activity.runOnUiThread(() -> {
+                    try {
+                        activity.startIntentSender(intent, fillInIntent, 0, 0, 0);
+                    } catch (IntentSender.SendIntentException e) {
+                        Log.e(TAG, "startIntentSender() failed for intent:" + intent, e);
+                    }
+                });
+            }
+        }
     };
 
-    private final WeakReference<Activity> mActivity;
+    private final AutoFillManager mAfm;
+    private WeakReference<Activity> mActivity;
 
-    @GuardedBy("this")
-    private VirtualViewDelegate.Callback mAutoFillDelegateCallback;
+    // Reference to the token, which is used by the server.
+    final WeakReference<IBinder> mToken;
 
-    public AutoFillSession(Activity activity) {
+    private boolean mEnabled;
+
+    public AutoFillSession(AutoFillManager afm, IBinder token) {
+        mToken = new WeakReference<>(token);
+        mAfm = afm;
+    }
+
+    /**
+     * Called by the {@link Activity} when it was asked to provider auto-fill data.
+     */
+    public void attachActivity(Activity activity) {
+        if (mActivity != null) {
+            Log.w(TAG, "attachActivity(): already attached");
+            return;
+        }
         mActivity = new WeakReference<>(activity);
     }
 
+    /**
+     * Checks whether auto-fill is enabled for this session, as decided by the
+     * {@code AutoFillManagerService}.
+     */
+    public boolean isEnabled() {
+        return mEnabled;
+    }
+
+    /**
+     * Notifies the manager that a session finished.
+     */
+    // TODO(b/33197203): hook it to other lifecycle events like fragments transition
+    public void finishSession() {
+        if (mAfm != null) {
+            try {
+                mAfm.reset();
+            } catch (RuntimeException e) {
+                Log.w(TAG, "Failed to finish session for " + mToken.get() + ": " + e);
+            }
+        }
+    }
+
     public IAutoFillAppCallback getCallback() {
         return mCallback;
     }
 
-    /**
-     * Lazily sets the {@link #mAutoFillDelegateCallback}.
-     */
-    private void setAutoFillDelegateCallback() {
-        synchronized (this) {
-            if (mAutoFillDelegateCallback == null) {
-                mAutoFillDelegateCallback = new VirtualViewDelegate.Callback() {
-                    // TODO(b/33197203): implement
-                };
-            }
-        }
-    }
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
 
+        return "AutoFillSession[activityoken=" + mToken.get() + "]";
+    }
 }
diff --git a/core/java/android/view/autofill/AutoFillValue.java b/core/java/android/view/autofill/AutoFillValue.java
index 57b23ef..af70361 100644
--- a/core/java/android/view/autofill/AutoFillValue.java
+++ b/core/java/android/view/autofill/AutoFillValue.java
@@ -18,6 +18,7 @@
 
 import static android.view.autofill.Helper.DEBUG;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.View;
@@ -32,12 +33,12 @@
  */
 public final class AutoFillValue implements Parcelable {
 
-    private final CharSequence mText;
+    private final String mText;
     private final int mListIndex;
     private final boolean mToggle;
 
     private AutoFillValue(CharSequence text, int listIndex, boolean toggle) {
-        mText = text;
+        mText = (text == null) ? null : text.toString();
         mListIndex = listIndex;
         mToggle = toggle;
     }
@@ -74,11 +75,40 @@
     /////////////////////////////////////
 
     @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mListIndex;
+        result = prime * result + ((mText == null) ? 0 : mText.hashCode());
+        result = prime * result + (mToggle ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final AutoFillValue other = (AutoFillValue) obj;
+        if (mListIndex != other.mListIndex) return false;
+        if (mText == null) {
+            if (other.mText != null) return false;
+        } else {
+            if (!mText.equals(other.mText)) return false;
+        }
+        if (mToggle != other.mToggle) return false;
+        return true;
+    }
+
+    @Override
     public String toString() {
         if (!DEBUG) return super.toString();
 
-        return "AutoFillValue[text=" + mText + ", listIndex=" + mListIndex + ", toggle=" + mToggle
-                + "]";
+        if (mText != null) {
+            return mText.length() + "_chars";
+        }
+
+        return "[listIndex=" + mListIndex + ", toggle=" + mToggle + "]";
     }
 
     /////////////////////////////////////
@@ -92,13 +122,13 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeCharSequence(mText);
+        parcel.writeString(mText);
         parcel.writeInt(mListIndex);
         parcel.writeInt(mToggle ? 1 : 0);
     }
 
     private AutoFillValue(Parcel parcel) {
-        mText = parcel.readCharSequence();
+        mText = parcel.readString();
         mListIndex = parcel.readInt();
         mToggle = parcel.readInt() == 1;
     }
@@ -127,8 +157,9 @@
      * <p>See {@link AutoFillType#isText()} for more info.
      */
     // TODO(b/33197203): use cache
-    public static AutoFillValue forText(CharSequence value) {
-        return new AutoFillValue(value, 0, false);
+    @Nullable
+    public static AutoFillValue forText(@Nullable CharSequence value) {
+        return value == null ? null : new AutoFillValue(value, 0, false);
     }
 
     /**
diff --git a/core/java/android/view/autofill/Dataset.java b/core/java/android/view/autofill/Dataset.java
index 18a08f9..2708358 100644
--- a/core/java/android/view/autofill/Dataset.java
+++ b/core/java/android/view/autofill/Dataset.java
@@ -17,12 +17,12 @@
 package android.view.autofill;
 
 import static android.view.autofill.Helper.DEBUG;
-import static android.view.autofill.Helper.append;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.assist.AssistStructure.ViewNode;
-import android.hardware.fingerprint.FingerprintManager.CryptoObject;
+import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -30,8 +30,6 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
 
 /**
  * A set of data that can be used to auto-fill an {@link Activity}.
@@ -44,221 +42,184 @@
  *   <li>An optional {@link Bundle} with extras (used only by the service creating it).
  * </ol>
  *
- * See {@link FillResponse} for examples.
+ * @see FillResponse for examples.
  */
 public final class Dataset implements Parcelable {
-
+    private final String mId;
     private final CharSequence mName;
-    private final ArrayList<DatasetField> mFields;
+    private final ArrayList<AutoFillId> mFieldIds;
+    private final ArrayList<AutoFillValue> mFieldValues;
     private final Bundle mExtras;
-    private final int mFlags;
-    private final boolean mRequiresAuth;
-    private final boolean mHasCryptoObject;
-    private final long mCryptoOpId;
+    private final IntentSender mAuthentication;
 
-    private Dataset(Dataset.Builder builder) {
+    private Dataset(Builder builder) {
+        mId = builder.mId;
         mName = builder.mName;
-        // TODO(b/33197203): make an immutable copy of mFields?
-        mFields = builder.mFields;
+        mFieldIds = builder.mFieldIds;
+        mFieldValues = builder.mFieldValues;
         mExtras = builder.mExtras;
-        mFlags = builder.mFlags;
-        mRequiresAuth = builder.mRequiresAuth;
-        mHasCryptoObject = builder.mHasCryptoObject;
-        mCryptoOpId = builder.mCryptoOpId;
+        mAuthentication = builder.mAuthentication;
     }
 
     /** @hide */
-    public CharSequence getName() {
+    public @NonNull String getId() {
+        return mId;
+    }
+
+    /** @hide */
+    public @NonNull CharSequence getName() {
         return mName;
     }
 
     /** @hide */
-    public List<DatasetField> getFields() {
-        return mFields;
+    public @Nullable ArrayList<AutoFillId> getFieldIds() {
+        return mFieldIds;
     }
 
     /** @hide */
-    public Bundle getExtras() {
+    public @Nullable ArrayList<AutoFillValue> getFieldValues() {
+        return mFieldValues;
+    }
+
+    /** @hide */
+    public @Nullable Bundle getExtras() {
         return mExtras;
     }
 
     /** @hide */
-    public int getFlags() {
-        return mFlags;
-    }
-
-    /** @hide */
-    public boolean isAuthRequired() {
-        return mRequiresAuth;
+    public @Nullable IntentSender getAuthentication() {
+        return mAuthentication;
     }
 
     /** @hide */
     public boolean isEmpty() {
-        return mFields.isEmpty();
-    }
-
-    /** @hide */
-    public boolean hasCryptoObject() {
-        return mHasCryptoObject;
-    }
-
-    /** @hide */
-    public long getCryptoObjectOpId() {
-        return mCryptoOpId;
+        return mFieldIds == null || mFieldIds.isEmpty();
     }
 
     @Override
     public String toString() {
         if (!DEBUG) return super.toString();
 
-        final StringBuilder builder = new StringBuilder("Dataset [name=").append(mName)
-                .append(", fields=").append(mFields).append(", extras=");
-        append(builder, mExtras)
-            .append(", flags=").append(mFlags)
-            .append(", requiresAuth: ").append(mRequiresAuth)
-            .append(", hasCrypto: ").append(mHasCryptoObject);
+        final StringBuilder builder = new StringBuilder("Dataset [id=").append(mId)
+                .append(", name=").append(mName)
+                .append(", fieldIds=").append(mFieldIds)
+                .append(", fieldValues=").append(mFieldValues)
+                .append(", hasAuthentication=").append(mAuthentication != null)
+                .append(", hasExtras=").append(mExtras != null);
         return builder.append(']').toString();
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Dataset other = (Dataset) obj;
+        if (mId == null) {
+            if (other.mId != null) {
+                return false;
+            }
+        } else if (!mId.equals(other.mId)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return mId != null ? mId.hashCode() : 0;
+    }
+
     /**
-     * A builder for {@link Dataset} objects.
+     * A builder for {@link Dataset} objects. You must to provide at least
+     * one value for a field or set an authentication intent.
      */
     public static final class Builder {
+        private String mId;
         private CharSequence mName;
-        private final ArrayList<DatasetField> mFields = new ArrayList<>();
+        private ArrayList<AutoFillId> mFieldIds;
+        private ArrayList<AutoFillValue> mFieldValues;
         private Bundle mExtras;
-        private int mFlags;
-        private boolean mRequiresAuth;
-        private boolean mHasCryptoObject;
-        private long mCryptoOpId;
+        private IntentSender mAuthentication;
+        private boolean mDestroyed;
+
+        /** @hide */
+        // TODO(b/33197203): Remove once GCore migrates
+        public Builder(@NonNull CharSequence name) {
+            this(String.valueOf(System.currentTimeMillis()), name);
+        }
 
         /**
          * Creates a new builder.
          *
+         * @param id A required id to identify this dataset for future interactions related to it.
          * @param name Name used to identify the dataset in the UI. Typically it's the same value as
-         * the first field in the dataset (like username or email address) or an user-provided name
+         * the first field in the dataset (like username or email address) or a user-provided name
          * (like "My Work Address").
          */
-        public Builder(CharSequence name) {
+        public Builder(@NonNull String id, @NonNull CharSequence name) {
+            mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty or null");
             mName = Preconditions.checkStringNotEmpty(name, "name cannot be empty or null");
         }
 
         /**
-         * Requires dataset authentication through the {@link
-         * android.service.autofill.AutoFillService} before auto-filling the activity with this
-         * dataset.
+         * Requires a dataset authentication before auto-filling the activity with this dataset.
          *
-         * <p>This method is typically called when the device (or the service) does not support
-         * fingerprint authentication (and hence it cannot use {@link
-         * #requiresFingerprintAuthentication(CryptoObject, Bundle, int)}) or when the service needs
-         * to use a custom authentication UI for the dataset. For example, when a dataset contains
-         * credit card information (such as number, expiration date, and verification code), the
-         * service displays an authentication dialog asking for the verification code to unlock the
-         * rest of the data).
+         * <p>This method is called when you need to provide an authentication
+         * UI for the dataset. For example, when a dataset contains credit card information
+         * (such as number, expiration date, and verification code), you can display UI
+         * asking for the verification code to before filing in the data). Even if the
+         * dataset is completely populated the system will launch the specified authentication
+         * intent and will need your approval to fill it in. Since the dataset is "locked"
+         * until the user authenticates it, typically this dataset name is masked
+         * (for example, "VISA....1234"). Typically you would want to store the dataset
+         * labels non-encypted and the actual sensitive data encrypted and not in memory.
+         * This allows showing the labels in the UI while involving the user if one of
+         * the items with these labels is chosen. Note that if you use sensitive data as
+         * a label, for example an email address, then it should also be encrypted.
+         *</p>
          *
-         * <p>Since the dataset is "locked" until the user authenticates it, typically this dataset
-         * name is masked (for example, "VISA....1234").
+         * <p>When a user selects this dataset, the system triggers the provided intent
+         * whose extras will have the {@link android.content.Intent#EXTRA_AUTO_FILL_ITEM_ID id}
+         * of the {@link android.view.autofill.Dataset dataset} to authenticate, the {@link
+         * android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras} associated with this
+         * dataset, and a {@link android.content.Intent#EXTRA_AUTO_FILL_CALLBACK callback}
+         * to dispatch the authentication result.</p>
          *
-         * <p>When the user selects this dataset, the Android System calls {@link
-         * android.service.autofill.AutoFillService#onDatasetAuthenticationRequest(Bundle, int)}
-         * passing {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_REQUESTED} in
-         * the flags and the same {@code extras} passed to this method. The service can then
-         * displays its custom authentication UI, and then call the proper method on {@link
-         * android.service.autofill.FillCallback} depending on the authentication result and whether
-         * this dataset already contains the fields needed to auto-fill the activity:
+         * <p>Once you complete your authentication flow you should use the provided callback
+         * to notify for a failure or a success. In case of a success you need to provide
+         * only the fully populated dataset that is being authenticated. For example, if you
+         * provided a {@link FillResponse} with two {@link Dataset}s and marked that
+         * only the first dataset needs an authentication then in the provided response
+         * you need to provide only the fully populated dataset being authenticated instead
+         * of both of them.
+         * </p>
          *
-         * <ul>
-         *   <li>If authentication failed, call
-         *   {@link android.service.autofill.FillCallback#onDatasetAuthentication(Dataset,
-         *       int)} passing {@link
-         *       android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_ERROR} in the flags.
-         *   <li>If authentication succeeded and this datast is empty (no fields), call {@link
-         *       android.service.autofill.FillCallback#onSuccess(FillResponse)} with a new dataset
-         *       (with the proper fields).
-         *   <li>If authentication succeeded and this response is not empty, call {@link
-         *       android.service.autofill.FillCallback#onDatasetAuthentication(Dataset, int)}
-         *       passing
-         *       {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_SUCCESS} in the
-         *       {@code flags} and {@code null} as the {@code dataset}.
-         * </ul>
+         * <p>The indent sender mechanism allows you to have your authentication UI
+         * implemented as an activity or a service or a receiver. However, the recommended
+         * way is to do this is with an activity which the system will start in the
+         * filled activity's task meaning it will properly work with back, recent apps, and
+         * free-form multi-window, while avoiding the need for the "draw on top of other"
+         * apps special permission. You can still theme your authentication activity's
+         * UI to look like a dialog if desired.</p>
          *
-         * @param extras when set, will be passed back in the {@link
-         *     android.service.autofill.AutoFillService#onDatasetAuthenticationRequest(Bundle,
-         *     int)}, call so it could be used by the service to handle state.
-         * @param flags optional parameters, currently ignored.
+         * <p></><strong>Note:</strong> Do not make the provided intent sender
+         * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
+         * platform needs to fill in the authentication arguments.</p>
+         *
+         * @param authentication Intent to trigger your authentication flow.
+         *
+         * @see android.app.PendingIntent#getIntentSender()
          */
-        public Builder requiresCustomAuthentication(@Nullable Bundle extras, int flags) {
-            return requiresAuthentication(null, extras, flags);
-        }
-
-        /**
-         * Requires dataset authentication through the Fingerprint sensor before auto-filling the
-         * activity with this dataset.
-         *
-         * <p>This method is typically called when the dataset contains sensitive information (for
-         * example, credit card information) and the provider requires the user to re-authenticate
-         * before using it.
-         *
-         * <p>Since the dataset is "locked" until the user authenticates it, typically this dataset
-         * name is masked (for example, "VISA....1234").
-         *
-         * <p>When the user selects this dataset, the Android System displays an UI affordance
-         * asking the user to use the fingerprint sensor unlock the dataset, and what happens after
-         * a successful fingerprint authentication depends on whether the dataset is empty (no
-         * fields, only the masked name) or not:
-         *
-         * <ul>
-         *   <li>If it's empty, the Android System will call {@link
-         *       android.service.autofill.AutoFillService#onDatasetAuthenticationRequest(Bundle,
-         *       int)} passing {@link
-         *       android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_SUCCESS}} in the
-         *       flags.
-         *   <li>If it's not empty, the activity will be auto-filled with its data.
-         * </ul>
-         *
-         * <p>If the fingerprint authentication fails, the Android System will call {@link
-         * android.service.autofill.AutoFillService#onDatasetAuthenticationRequest(Bundle, int)}
-         * passing {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_ERROR} in the
-         * flags.
-         *
-         * <p><strong>NOTE: </note> the {@link android.service.autofill.AutoFillService} should use
-         * the {@link android.hardware.fingerprint.FingerprintManager} to check if fingerpint
-         * authentication is available before using this method, and use other alternatives (such as
-         * {@link #requiresCustomAuthentication(Bundle, int)}) if it is not: if this method is
-         * called when fingerprint is not available, Android System will call {@link
-         * android.service.autofill.AutoFillService#onDatasetAuthenticationRequest(Bundle, int)}
-         * passing {@link
-         * android.service.autofill.AutoFillService#FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE}
-         * in the flags, but it would be wasting system resources (and worsening the user
-         * experience) in the process.
-         *
-         * @param crypto object that will be authenticated.
-         * @param extras when set, will be passed back in the {@link
-         *     android.service.autofill.AutoFillService#onDatasetAuthenticationRequest(Bundle, int)}
-         *     call so it could be used by the service to handle state.
-         * @param flags optional parameters, currently ignored.
-         */
-        public Builder requiresFingerprintAuthentication(CryptoObject crypto,
-                @Nullable Bundle extras, int flags) {
-            // TODO(b/33197203): should we allow crypto to be null?
-            Preconditions.checkArgument(crypto != null, "must pass a CryptoObject");
-            return requiresAuthentication(crypto, extras, flags);
-        }
-
-        private Builder requiresAuthentication(CryptoObject cryptoObject, Bundle extras,
-                int flags) {
-            // There can be only one!
-            Preconditions.checkState(!mRequiresAuth,
-                    "requires-authentication methods already called");
-            // TODO(b/33197203): make sure that either this method or setExtras() is called, but
-            // not both
-            mExtras = extras;
-            mFlags = flags;
-            mRequiresAuth = true;
-            if (cryptoObject != null) {
-                mHasCryptoObject = true;
-                mCryptoOpId = cryptoObject.getOpId();
-            }
+        public @NonNull Builder setAuthentication(@Nullable IntentSender authentication) {
+            throwIfDestroyed();
+            mAuthentication = authentication;
             return this;
         }
 
@@ -268,41 +229,55 @@
          * @param id id returned by {@link ViewNode#getAutoFillId()}.
          * @param value value to be auto filled.
          */
-        public Dataset.Builder setValue(AutoFillId id, AutoFillValue value) {
-            putField(new DatasetField(id, value));
+        public @NonNull Builder setValue(@NonNull AutoFillId id, @NonNull AutoFillValue value) {
+            throwIfDestroyed();
+            Preconditions.checkNotNull(id, "id cannot be null");
+            Preconditions.checkNotNull(value, "value cannot be null");
+            if (mFieldIds != null) {
+                final int existingIdx = mFieldIds.indexOf(id);
+                if (existingIdx >= 0) {
+                    mFieldValues.set(existingIdx, value);
+                    return this;
+                }
+            } else {
+                mFieldIds = new ArrayList<>();
+                mFieldValues = new ArrayList<>();
+            }
+            mFieldIds.add(id);
+            mFieldValues.add(value);
             return this;
         }
 
         /**
-         * Creates a new {@link Dataset} instance.
+         * Sets a {@link Bundle} that will be passed to subsequent APIs that
+         * manipulate this dataset. For example, they are passed in as {@link
+         * android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras} to your
+         * authentication flow.
          */
-        public Dataset build() {
+        public @NonNull Builder setExtras(@Nullable Bundle extras) {
+            throwIfDestroyed();
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Creates a new {@link Dataset} instance. You should not interact
+         * with this builder once this method is called.
+         */
+        public @NonNull Dataset build() {
+            throwIfDestroyed();
+            mDestroyed = true;
+            if (mFieldIds == null && mAuthentication == null) {
+                throw new IllegalArgumentException(
+                        "at least one value or an authentication must be set");
+            }
             return new Dataset(this);
         }
 
-        /**
-         * Sets a {@link Bundle} that will be passed to subsequent calls to
-         * {@link android.service.autofill.AutoFillService} methods such as
- * {@link android.service.autofill.AutoFillService#onSaveRequest(android.app.assist.AssistStructure,
-         * Bundle, android.service.autofill.SaveCallback)}, using
-         * {@link android.service.autofill.AutoFillService#EXTRA_DATASET_EXTRAS} as the key.
-         *
-         * <p>It can be used to keep service state in between calls.
-         */
-        public Builder setExtras(Bundle extras) {
-            // TODO(b/33197203): make sure that either this method or the requires-Authentication
-            // ones are called, but not both
-            mExtras = Objects.requireNonNull(extras, "extras cannot be null");
-            return this;
-        }
-
-        /**
-         * Emulates {@code Map.put()} by adding a new field to the list if its id is not the yet,
-         * or replacing the existing one.
-         */
-        private void putField(DatasetField field) {
-            // TODO(b/33197203): check if already exists and replaces it if so
-            mFields.add(field);
+        private void throwIfDestroyed() {
+            if (mDestroyed) {
+                throw new IllegalStateException("Already called #build()");
+            }
         }
     }
 
@@ -317,32 +292,33 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mId);
         parcel.writeCharSequence(mName);
-        parcel.writeList(mFields);
+        parcel.writeTypedArrayList(mFieldIds, 0);
+        parcel.writeTypedArrayList(mFieldValues, 0);
         parcel.writeBundle(mExtras);
-        parcel.writeInt(mFlags);
-        parcel.writeInt(mRequiresAuth ? 1 : 0);
-        parcel.writeInt(mHasCryptoObject ? 1 : 0);
-        if (mHasCryptoObject) {
-            parcel.writeLong(mCryptoOpId);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private Dataset(Parcel parcel) {
-        mName = parcel.readCharSequence();
-        mFields = parcel.readArrayList(null);
-        mExtras = parcel.readBundle();
-        mFlags = parcel.readInt();
-        mRequiresAuth = parcel.readInt() == 1;
-        mHasCryptoObject = parcel.readInt() == 1;
-        mCryptoOpId = mHasCryptoObject ? parcel.readLong() : 0;
+        parcel.writeParcelable(mAuthentication, flags);
     }
 
     public static final Parcelable.Creator<Dataset> CREATOR = new Parcelable.Creator<Dataset>() {
         @Override
-        public Dataset createFromParcel(Parcel source) {
-            return new Dataset(source);
+        public Dataset createFromParcel(Parcel parcel) {
+            // Always go through the builder to ensure the data ingested by
+            // the system obeys the contract of the builder to avoid attacks
+            // using specially crafted parcels.
+            final Builder builder = new Builder(parcel.readString(), parcel.readCharSequence());
+            final ArrayList<AutoFillId> ids = parcel.readTypedArrayList(null);
+            final ArrayList<AutoFillValue> values = parcel.readTypedArrayList(null);
+            final int idCount = (ids != null) ? ids.size() : 0;
+            final int valueCount = (values != null) ? values.size() : 0;
+            for (int i = 0; i < idCount; i++) {
+                AutoFillId id = ids.get(i);
+                AutoFillValue value = (valueCount > i) ? values.get(i) : null;
+                builder.setValue(id, value);
+            }
+            builder.setExtras(parcel.readBundle());
+            builder.setAuthentication(parcel.readParcelable(null));
+            return builder.build();
         }
 
         @Override
diff --git a/core/java/android/view/autofill/DatasetField.java b/core/java/android/view/autofill/DatasetField.java
deleted file mode 100644
index c6b92ac..0000000
--- a/core/java/android/view/autofill/DatasetField.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.autofill;
-
-import static android.view.autofill.Helper.DEBUG;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public final class DatasetField implements Parcelable {
-
-    private final AutoFillId mId;
-    private final AutoFillValue mValue;
-
-    DatasetField(AutoFillId id, AutoFillValue value) {
-        mId = id;
-        mValue = value;
-    }
-
-    public AutoFillId getId() {
-        return mId;
-    }
-
-    public AutoFillValue getValue() {
-        return mValue;
-    }
-
-    /////////////////////////////////
-    //  Object "contract" methods. //
-    /////////////////////////////////
-
-    @Override
-    public String toString() {
-        if (!DEBUG) return super.toString();
-
-        return "DatasetField [id=" + mId + ", value=" + mValue + "]";
-    }
-
-    /////////////////////////////////////
-    //  Parcelable "contract" methods. //
-    /////////////////////////////////////
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeParcelable(mId, 0);
-        parcel.writeParcelable(mValue, 0);
-    }
-
-    private DatasetField(Parcel parcel) {
-        mId = parcel.readParcelable(null);
-        mValue = parcel.readParcelable(null);
-    }
-
-    public static final Parcelable.Creator<DatasetField> CREATOR =
-            new Parcelable.Creator<DatasetField>() {
-        @Override
-        public DatasetField createFromParcel(Parcel source) {
-            return new DatasetField(source);
-        }
-
-        @Override
-        public DatasetField[] newArray(int size) {
-            return new DatasetField[size];
-        }
-    };
-}
diff --git a/core/java/android/view/autofill/FillResponse.java b/core/java/android/view/autofill/FillResponse.java
index 48dbb84..596a06c 100644
--- a/core/java/android/view/autofill/FillResponse.java
+++ b/core/java/android/view/autofill/FillResponse.java
@@ -16,36 +16,30 @@
 package android.view.autofill;
 
 import static android.view.autofill.Helper.DEBUG;
-import static android.view.autofill.Helper.append;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
-import android.hardware.fingerprint.FingerprintManager.CryptoObject;
+import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.service.autofill.FillCallback;
+import android.util.ArraySet;
 
 import com.android.internal.util.Preconditions;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
 /**
  * Response for a {@link
  * android.service.autofill.AutoFillService#onFillRequest(android.app.assist.AssistStructure,
- * Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback)} request.
+ * Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback)} and
+ * authentication requests.
  *
  * <p>The response typically contains one or more {@link Dataset}s, each representing a set of
- * fields that can be auto-filled together, and the Android System displays a dataset picker UI
+ * fields that can be auto-filled together, and the Android system displays a dataset picker UI
  * affordance that the user must use before the {@link Activity} is filled with the dataset.
  *
  * <p>For example, for a login page with username/password where the user only has one account in
- * the service, the response could be:
+ * the response could be:
  *
  * <pre class="prettyprint">
  *  new FillResponse.Builder()
@@ -102,12 +96,17 @@
  * <p>Notice that the ids that are part of a dataset (ids 1 to 4, in this example) are automatically
  * added to the {@code savableIds} list.
  *
- * <p>If the service has multiple {@link Dataset}s with multiple options for some fields on each
- * dataset (for example, multiple accounts with both a home and work address), then it should
- * "partition" the {@link Activity} in sections and populate the response with just a subset of the
- * data that would fulfill the first section; then once the user fills the first section and taps a
- * field from the next section, the Android system would issue another request for that section, and
- * so on. For example, the first response could be:
+ * <p>If the service has multiple {@link Dataset}s for different sections of the activity,
+ * for example, a user section for which there are two datasets followed by an address
+ * section for which there are two datasets for each user user, then it should "partition"
+ * the activity in sections and populate the response with just a subset of the data that would
+ * fulfill the first section (the name in our example); then once the user fills the first
+ * section and taps a field from the next section (the address in our example), the Android
+ * system would issue another request for that section, and so on. Note that if the user
+ * chooses to populate the first section with a service provided dataset, the subsequent request
+ * would contain the populated values so you don't try to provide suggestions for the first
+ * section but ony for the second one based on the context of what was already filled. For
+ * example, the first response could be:
  *
  * <pre class="prettyprint">
  *  new FillResponse.Builder()
@@ -132,236 +131,182 @@
  *          .setTextFieldValue(id4, "Springfield")
  *          .build())
  *      .add(new Dataset.Builder("Work")
- *          .setTextFieldValue(id3, "Springfield Nuclear Power Plant")
+ *          .setTextFieldValue(id3, "Springfield Power Plant")
  *          .setTextFieldValue(id4, "Springfield")
  *          .build())
  *      .build();
  * </pre>
  *
- * <p>The service could require user authentication, either at the {@link FillResponse} or {@link
- * Dataset} levels, prior to auto-filling the activity - see {@link
- * FillResponse.Builder#requiresFingerprintAuthentication(CryptoObject, Bundle, int)}, {@link
- * FillResponse.Builder#requiresCustomAuthentication(Bundle, int)}, {@link
- * Dataset.Builder#requiresFingerprintAuthentication(CryptoObject, Bundle, int)}, and {@link
- * Dataset.Builder#requiresCustomAuthentication(Bundle, int)} for details.
+ * <p>The service could require user authentication at the {@link FillResponse} or the
+ * {@link Dataset} level, prior to auto-filling an activity - see {@link FillResponse.Builder
+ * #setAuthentication(IntentSender)} and {@link Dataset.Builder#setAuthentication(IntentSender)}.
+ * It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
+ * which would allow you to provide the dataset names to the user and if they choose one
+ * them challenge the user to authenticate. For example, if the user has a home and a work
+ * address the Home and Work labels could be stored unencrypted as they don't have any sensitive
+ * data while the address data is in an encrypted storage. If the user chooses Home, then the
+ * platform will start your authentication flow. If you encrypt all data and require auth
+ * at the response level the user will have to interact with the fill UI to trigger a request
+ * for the datasets as they don't see Home and Work options which will trigger your auth
+ * flow and after successfully authenticating the user will be presented with the Home and
+ * Work options where they can pick one. Hence, you have flexibility how to implement your
+ * auth while storing labels non-encrypted and data encrypted provides a better user
+ * experience.</p>
  *
- * <p>Finally, the service can use the {@link FillResponse.Builder#setExtras(Bundle)} and/or {@link
- * Dataset.Builder#setExtras(Bundle)} methods to pass {@link Bundle}s with service-specific data use
- * to identify this response on future calls (like {@link
- * android.service.autofill.AutoFillService#onSaveRequest(android.app.assist.AssistStructure,
- * Bundle, android.service.autofill.SaveCallback)}) - such bundles will be available as the
- * {@link android.service.autofill.AutoFillService#EXTRA_RESPONSE_EXTRAS} and
- * {@link android.service.autofill.AutoFillService#EXTRA_DATASET_EXTRAS} extras in that method's
- * {@code extras} argument.
+ * <p>Finally, the service can use {@link Dataset.Builder#setExtras(Bundle)} methods
+ * to pass {@link Bundle extras} provided to all future calls related to a dataset,
+ * for example during authentication and saving.</p>
  */
 public final class FillResponse implements Parcelable {
-
-    private final List<Dataset> mDatasets;
-    private final AutoFillId[] mSavableIds;
+    private final String mId;
+    private final ArraySet<Dataset> mDatasets;
+    private final ArraySet<AutoFillId> mSavableIds;
     private final Bundle mExtras;
-    private final int mFlags;
-    private final boolean mRequiresAuth;
-    private final boolean mHasCryptoObject;
-    private final long mCryptoOpId;
+    private final IntentSender mAuthentication;
 
-    private FillResponse(Builder builder) {
-        // TODO(b/33197203): make it immutable?
+    private FillResponse(@NonNull Builder builder) {
+        mId = builder.mId;
         mDatasets = builder.mDatasets;
-        final int size = builder.mSavableIds.size();
-        mSavableIds = new AutoFillId[size];
-        int i = 0;
-        for (AutoFillId id : builder.mSavableIds) {
-            mSavableIds[i++] = id;
-        }
+        mSavableIds = builder.mSavableIds;
         mExtras = builder.mExtras;
-        mFlags = builder.mFlags;
-        mRequiresAuth = builder.mRequiresAuth;
-        mHasCryptoObject = builder.mHasCryptoObject;
-        mCryptoOpId = builder.mCryptoOpId;
+        mAuthentication = builder.mAuthentication;
     }
 
     /** @hide */
-    public List<Dataset> getDatasets() {
-        return mDatasets;
+    public @NonNull String getId() {
+        return mId;
     }
 
     /** @hide */
-    public AutoFillId[] getSavableIds() {
-        return mSavableIds;
-    }
-
-    /** @hide */
-    public Bundle getExtras() {
+    public @Nullable Bundle getExtras() {
         return mExtras;
     }
 
     /** @hide */
-    public int getFlags() {
-        return mFlags;
+    public @Nullable ArraySet<Dataset> getDatasets() {
+        return mDatasets;
     }
 
     /** @hide */
-    public boolean isAuthRequired() {
-        return mRequiresAuth;
+    public @Nullable ArraySet<AutoFillId> getSavableIds() {
+        return mSavableIds;
     }
 
     /** @hide */
-    public boolean hasCryptoObject() {
-        return mHasCryptoObject;
-    }
-
-    /** @hide */
-    public long getCryptoObjectOpId() {
-        return mCryptoOpId;
+    public @Nullable IntentSender getAuthentication() {
+        return mAuthentication;
     }
 
     /**
-     * Builder for {@link FillResponse} objects.
+     * Builder for {@link FillResponse} objects. You must to provide at least
+     * one dataset or set an authentication intent.
      */
     public static final class Builder {
-        private final List<Dataset> mDatasets = new ArrayList<>();
-        private final Set<AutoFillId> mSavableIds = new HashSet<>();
+        private final String mId;
+        private ArraySet<Dataset> mDatasets;
+        private ArraySet<AutoFillId> mSavableIds;
         private Bundle mExtras;
-        private int mFlags;
-        private boolean mRequiresAuth;
-        private boolean mHasCryptoObject;
-        private long mCryptoOpId;
+        private IntentSender mAuthentication;
+        private boolean mDestroyed;
 
-        /**
-         * Requires user authentication through the {@link android.service.autofill.AutoFillService}
-         * before handling an auto-fill request.
-         *
-         * <p>This method is typically called when the device (or the service) does not support
-         * fingerprint authentication (and hence it cannot use {@link
-         * #requiresFingerprintAuthentication(CryptoObject, Bundle, int)}) or when the service needs
-         * to use a custom authentication UI and is used in 2 scenarios:
-         *
-         * <ol>
-         *   <li>When the user data is encrypted and the service must authenticate an object that
-         *       will be used to decrypt it.
-         *   <li>When the service already acquired the user data but wants to confirm the user's
-         *       identity before the activity is filled with it.
-         * </ol>
-         *
-         * <p>When this method is called, the Android System displays an UI affordance asking the
-         * user to tap it to auto-fill the activity; if the user taps it, the Android System calls
-         * {@link
-         * android.service.autofill.AutoFillService#onFillResponseAuthenticationRequest(Bundle,
-         * int)} passing {@link
-         * android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_REQUESTED} in the flags and
-         * the same {@code extras} passed to this method. The service can then displays its custom
-         * authentication UI, and then call the proper method on {@link FillCallback} depending on
-         * the authentication result and whether this response already contains the {@link Dataset}s
-         * need to auto-fill the activity:
-         *
-         * <ul>
-         *   <li>If authentication failed, call {@link
-         *       FillCallback#onFillResponseAuthentication(int)} passing {@link
-         *       android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_ERROR} in the flags.
-         *   <li>If authentication succeeded and this response is empty (no datasets), call {@link
-         *       FillCallback#onSuccess(FillResponse)} with a new dataset (that does not require
-         *       authentication).
-         *   <li>If authentication succeeded and this response is not empty, call {@link
-         *       FillCallback#onFillResponseAuthentication(int)} passing {@link
-         *       android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_SUCCESS} in the flags.
-         * </ul>
-         *
-         * @param extras when set, will be passed back in the {@link
-         *     android.service.autofill.AutoFillService#onFillResponseAuthenticationRequest(Bundle,
-         *     int)} call so it could be used by the service to handle state.
-         * @param flags optional parameters, currently ignored.
-         */
-        public Builder requiresCustomAuthentication(@Nullable Bundle extras, int flags) {
-            return requiresAuthentication(null, extras, flags);
+        /** @hide */
+        // TODO(b/33197203): Remove once GCore migrates
+        public Builder() {
+            this(String.valueOf(System.currentTimeMillis()));
         }
 
         /**
-         * Requires user authentication through the Fingerprint sensor before handling an auto-fill
-         * request.
+         * Creates a new {@link FillResponse} builder.
          *
-         * <p>The {@link android.service.autofill.AutoFillService} typically uses this method in 2
-         * situations:
-         *
-         * <ol>
-         *   <li>When the user data is encrypted and the service must authenticate an object that
-         *       will be used to decrypt it.
-         *   <li>When the service already acquired the user data but wants to confirm the user's
-         *       identity before the activity is filled with it.
-         * </ol>
-         *
-         * <p>When this method is called, the Android System displays an UI affordance asking the
-         * user to use the fingerprint sensor to auto-fill the activity, and what happens after a
-         * successful fingerprint authentication depends on the number of {@link Dataset}s included
-         * in this response:
-         *
-         * <ul>
-         *   <li>If it's empty (scenario #1 above), the Android System will call {@link
-         *     android.service.autofill.AutoFillService#onFillResponseAuthenticationRequest(Bundle,
-         *       int)} passing {@link
-         *       android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_SUCCESS}} in the
-         *       flags.
-         *   <li>If it contains one dataset, the activity will be auto-filled right away.
-         *   <li>If it contains many datasets, the Android System will show dataset picker UI, and
-         *       then auto-fill the activity once the user select the proper datased.
-         * </ul>
-         *
-         * <p>If the fingerprint authentication fails, the Android System will call {@link
-         * android.service.autofill.AutoFillService#onFillResponseAuthenticationRequest(Bundle,
-         * int)} passing {@link android.service.autofill.AutoFillService#FLAG_AUTHENTICATION_ERROR}
-         * in the flags.
-         *
-         * <p><strong>NOTE: </note> the {@link android.service.autofill.AutoFillService} should use
-         * the {@link android.hardware.fingerprint.FingerprintManager} to check if fingerpint
-         * authentication is available before using this method, and use other alternatives (such as
-         * {@link #requiresCustomAuthentication(Bundle, int)}) if it is not: if this method is
-         * called when fingerprint is not available, Android System will call {@link
-         * android.service.autofill.AutoFillService#onFillResponseAuthenticationRequest(Bundle,
-         * int)} passing {@link
-         * android.service.autofill.AutoFillService#FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE}
-         * in the flags, but it would be wasting system resources (and worsening the user
-         * experience) in the process.
-         *
-         * @param crypto object that will be authenticated.
-         * @param extras when set, will be passed back in the {@link
-         *     android.service.autofill.AutoFillService#onFillResponseAuthenticationRequest(Bundle,
-         *     int)} call so it could be used by the service to handle state.
-         * @param flags optional parameters, currently ignored.
+         * @param id A required id to identify this dataset for future interactions related to it.
          */
-        public Builder requiresFingerprintAuthentication(CryptoObject crypto,
-                @Nullable Bundle extras, int flags) {
-            // TODO(b/33197203): should we allow crypto to be null?
-            Preconditions.checkArgument(crypto != null, "must pass a CryptoObject");
-            return requiresAuthentication(crypto, extras, flags);
+        public Builder(@NonNull String id) {
+            mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty or null");
         }
 
-        private Builder requiresAuthentication(CryptoObject cryptoObject, Bundle extras,
-                int flags) {
-            // There can be only one!
-            Preconditions.checkState(!mRequiresAuth,
-                    "requires-authentication methods already called");
-            // TODO(b/33197203): make sure that either this method or setExtras() is called, but
-            // not both
-            mExtras = extras;
-            mFlags = flags;
-            mRequiresAuth = true;
-            if (cryptoObject != null) {
-                mHasCryptoObject = true;
-                mCryptoOpId = cryptoObject.getOpId();
-            }
+        /**
+         * Requires a fill response authentication before auto-filling the activity with
+         * any dataset in this response. This is typically useful when a user interaction
+         * is required to unlock their data vault if you encrypt the dataset labels and
+         * dataset data. It is recommended to encrypt only the sensitive data and not the
+         * dataset labels which would allow auth on the dataset level leading to a better
+         * user experience. Note that if you use sensitive data as a label, for example an
+         * email address, then it should also be encrypted.
+         *
+         * <p>This method is called when you need to provide an authentication
+         * UI for the fill response. For example, when the user's data is stored
+         * encrypted and needs a user interaction to decrypt before offering fill
+         * suggestions.</p>
+         *
+         * <p>When a user initiates an auto fill, the system triggers the provided
+         * intent whose extras will have the {@link android.content.Intent
+         * #EXTRA_AUTO_FILL_ITEM_ID id} of the {@link android.view.autofill.FillResponse})
+         * to authenticate, the {@link android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras}
+         * associated with this response, and a {@link android.content.Intent
+         * #EXTRA_AUTO_FILL_CALLBACK callback} to dispatch the authentication result.</p>
+         *
+         * <p>Once you complete your authentication flow you should use the provided callback
+         * to notify for a failure or a success. In case of a success you need to provide
+         * the fully populated response that is being authenticated. For example, if you
+         * provided an empty {@link FillResponse} because the user's data was locked and
+         * marked that the response needs an authentication then in the response returned
+         * if authentication succeeds you need to provide all available datasets some of
+         * which may need to be further authenticated, for example a credit card whose
+         * CVV needs to be entered.</p>
+         *
+         * <p>The indent sender mechanism allows you to have your authentication UI
+         * implemented as an activity or a service or a receiver. However, the recommended
+         * way is to do this is with an activity which the system will start in the
+         * filled activity's task meaning it will properly work with back, recent apps, and
+         * free-form multi-window, while avoiding the need for the "draw on top of other"
+         * apps special permission. You can still theme your authentication activity's
+         * UI to look like a dialog if desired.</p>
+         *
+         * <p></><strong>Note:</strong> Do not make the provided intent sender
+         * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
+         * platform needs to fill in the authentication arguments.</p>
+         *
+         * @param authentication Intent to trigger your authentication flow.
+         *
+         * @see android.app.PendingIntent#getIntentSender()
+         */
+        public @NonNull Builder setAuthentication(@Nullable IntentSender authentication) {
+            throwIfDestroyed();
+            mAuthentication = authentication;
             return this;
         }
 
         /**
-         * Adds a new {@link Dataset} to this response.
+         * Adds a new {@link Dataset} to this response. Adding a dataset with the
+         * same id updates the existing one.
          *
          * @throws IllegalArgumentException if a dataset with same {@code name} already exists.
          */
-        public Builder addDataset(Dataset dataset) {
-            Preconditions.checkNotNull(dataset, "dataset cannot be null");
-            // TODO(b/33197203): check if name already exists
-            mDatasets.add(dataset);
-            for (DatasetField field : dataset.getFields()) {
-                mSavableIds.add(field.getId());
+        public@NonNull Builder addDataset(@Nullable Dataset dataset) {
+            throwIfDestroyed();
+            if (dataset == null) {
+                return this;
+            }
+            if (mDatasets == null) {
+                mDatasets = new ArraySet<>();
+            }
+            final int datasetCount = mDatasets.size();
+            for (int i = 0; i < datasetCount; i++) {
+                if (mDatasets.valueAt(i).getName().equals(dataset.getName())) {
+                    throw new IllegalArgumentException("Duplicate dataset name: "
+                            + dataset.getName());
+                }
+            }
+            if (!mDatasets.add(dataset)) {
+                return this;
+            }
+            final int fieldCount = dataset.getFieldIds().size();
+            for (int i = 0; i < fieldCount; i++) {
+                final AutoFillId id = dataset.getFieldIds().get(i);
+                if (mSavableIds == null) {
+                    mSavableIds = new ArraySet<>();
+                }
+                mSavableIds.add(id);
             }
             return this;
         }
@@ -374,27 +319,35 @@
          *
          * <p>See {@link FillResponse} for examples.
          */
-        public Builder addSavableFields(AutoFillId... ids) {
+        public @NonNull Builder addSavableFields(@Nullable AutoFillId... ids) {
+            throwIfDestroyed();
+            if (ids == null) {
+                return this;
+            }
             for (AutoFillId id : ids) {
+                if (mSavableIds == null) {
+                    mSavableIds = new ArraySet<>();
+                }
                 mSavableIds.add(id);
             }
             return this;
         }
 
         /**
-         * Sets a {@link Bundle} that will be passed to subsequent calls to {@link
-         * android.service.autofill.AutoFillService} methods such as {@link
+         * Sets a {@link Bundle} that will be passed to subsequent APIs that
+         * manipulate this response. For example, they are passed in as {@link
+         * android.content.Intent#EXTRA_AUTO_FILL_EXTRAS extras} to your
+         * authentication flow and to subsequent calls to {@link
+         * android.service.autofill.AutoFillService#onFillRequest(
+         * android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal,
+         * android.service.autofill.FillCallback)} and {@link
          * android.service.autofill.AutoFillService#onSaveRequest(
-         * android.app.assist.AssistStructure, Bundle, android.service.autofill.SaveCallback)},
-         * using {@link
-         * android.service.autofill.AutoFillService#EXTRA_RESPONSE_EXTRAS} as the key.
-         *
-         * <p>It can be used when to keep service state in between calls.
+         * android.app.assist.AssistStructure, Bundle,
+         * android.service.autofill.SaveCallback)}.
          */
         public Builder setExtras(Bundle extras) {
-            // TODO(b/33197203): make sure that either this method or the requires-Authentication
-            // ones are called, but not both
-            mExtras = Objects.requireNonNull(extras, "extras cannot be null");
+            throwIfDestroyed();
+            mExtras = extras;
             return this;
         }
 
@@ -402,8 +355,16 @@
          * Builds a new {@link FillResponse} instance.
          */
         public FillResponse build() {
+            throwIfDestroyed();
+            mDestroyed = true;
             return new FillResponse(this);
         }
+
+        private void throwIfDestroyed() {
+            if (mDestroyed) {
+                throw new IllegalStateException("Already called #build()");
+            }
+        }
     }
 
     /////////////////////////////////////
@@ -412,14 +373,12 @@
     @Override
     public String toString() {
         if (!DEBUG) return super.toString();
-
-        final StringBuilder builder = new StringBuilder("FillResponse: [datasets=")
-                .append(mDatasets).append(", savableIds=").append(Arrays.toString(mSavableIds))
-                .append(", extras=");
-        append(builder, mExtras)
-            .append(", flags=").append(mFlags)
-            .append(", requiresAuth: ").append(mRequiresAuth)
-            .append(", hasCrypto: ").append(mHasCryptoObject);
+        final StringBuilder builder = new StringBuilder(
+                "FillResponse: [id=").append(mId)
+                .append(", datasets=").append(mDatasets)
+                .append(", savableIds=").append(mSavableIds)
+                .append(", hasExtras=").append(mExtras != null)
+                .append(", hasAuthentication=").append(mAuthentication != null);
         return builder.append(']').toString();
     }
 
@@ -434,33 +393,34 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeList(mDatasets);
-        parcel.writeParcelableArray(mSavableIds, 0);
-        parcel.writeBundle(mExtras);
-        parcel.writeInt(mFlags);
-        parcel.writeInt(mRequiresAuth ? 1 : 0);
-        parcel.writeInt(mHasCryptoObject ? 1 : 0);
-        if (mHasCryptoObject) {
-            parcel.writeLong(mCryptoOpId);
-        }
-    }
-
-    private FillResponse(Parcel parcel) {
-        mDatasets = new ArrayList<>();
-        parcel.readList(mDatasets, null);
-        mSavableIds = parcel.readParcelableArray(null, AutoFillId.class);
-        mExtras = parcel.readBundle();
-        mFlags = parcel.readInt();
-        mRequiresAuth = parcel.readInt() == 1;
-        mHasCryptoObject = parcel.readInt() == 1;
-        mCryptoOpId = mHasCryptoObject ? parcel.readLong() : 0;
+        parcel.writeString(mId);
+        parcel.writeTypedArraySet(mDatasets, 0);
+        parcel.writeTypedArraySet(mSavableIds, 0);
+        parcel.writeParcelable(mExtras, 0);
+        parcel.writeParcelable(mAuthentication, 0);
     }
 
     public static final Parcelable.Creator<FillResponse> CREATOR =
             new Parcelable.Creator<FillResponse>() {
         @Override
-        public FillResponse createFromParcel(Parcel source) {
-            return new FillResponse(source);
+        public FillResponse createFromParcel(Parcel parcel) {
+            // Always go through the builder to ensure the data ingested by
+            // the system obeys the contract of the builder to avoid attacks
+            // using specially crafted parcels.
+            final Builder builder = new Builder(parcel.readString());
+            final ArraySet<Dataset> datasets = parcel.readTypedArraySet(null);
+            final int datasetCount = (datasets != null) ? datasets.size() : 0;
+            for (int i = 0; i < datasetCount; i++) {
+                builder.addDataset(datasets.valueAt(i));
+            }
+            final ArraySet<AutoFillId> fillIds = parcel.readTypedArraySet(null);
+            final int fillIdCount = (fillIds != null) ? fillIds.size() : 0;
+            for (int i = 0; i < fillIdCount; i++) {
+                builder.addSavableFields(fillIds.valueAt(i));
+            }
+            builder.setExtras(parcel.readParcelable(null));
+            builder.setAuthentication(parcel.readParcelable(null));
+            return builder.build();
         }
 
         @Override
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
index 14cf9e8..b1c9efa 100644
--- a/core/java/android/view/autofill/Helper.java
+++ b/core/java/android/view/autofill/Helper.java
@@ -26,12 +26,13 @@
 public final class Helper {
 
     static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
+    static final boolean VERBOSE = false;
     static final String REDACTED = "[REDACTED]";
 
     static StringBuilder append(StringBuilder builder, Bundle bundle) {
         if (bundle == null) {
             builder.append("N/A");
-        } else if (!DEBUG) {
+        } else if (!VERBOSE) {
             builder.append(REDACTED);
         } else {
             final Set<String> keySet = bundle.keySet();
diff --git a/core/java/android/view/autofill/VirtualViewDelegate.java b/core/java/android/view/autofill/VirtualViewDelegate.java
deleted file mode 100644
index e465c67..0000000
--- a/core/java/android/view/autofill/VirtualViewDelegate.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.view.autofill;
-
-import android.annotation.Nullable;
-import android.graphics.Rect;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewStructure;
-
-/**
- * This class is the contract a client should implement to enable support of a
- * virtual view hierarchy rooted at a given view for auto-fill purposes.
- *
- * <p>The view hierarchy is typically created through the
- * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)} call and client
- * add virtual children by calling {@link ViewStructure#newChild(int, int, int)} or
- * {@link ViewStructure#asyncNewChild(int, int, int)}, where the client provides the
- * {@code virtualId} of the children - the same {@code virtualId} is used in the methods of this
- * class.
- *
- * <p>Objects of this class are typically created by overriding
- * {@link View#getAutoFillVirtualViewDelegate(Callback)} and saving the passed callback, which must
- * be notified upon changes on the hierarchy.
- *
- * <p>The main use case of these API is to enable custom views that draws its content - such as
- * {@link android.webkit.WebView} providers - to support the AutoFill Framework:
- *
- * <ol>
- *   <li>Client populates the virtual hierarchy on
- * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}
- *   <li>Android System generates the proper {@link AutoFillId} - encapsulating the view and the
- * virtual node ids - and pass it to the {@link android.service.autofill.AutoFillService}.
- *   <li>The service uses the {@link AutoFillId} to populate the auto-fill {@link Dataset}s and pass
- *   it back to the Android System.
- *   <li>Android System uses the {@link AutoFillId} to find the proper custom view and calls
- *   {@link #autoFill(int, AutoFillValue)} on that view passing the virtual id.
- *   <li>This provider than finds the node in the hierarchy and auto-fills it.
- * </ol>
- *
- */
-public abstract class VirtualViewDelegate {
-
-    // TODO(b/33197203): set to false once stable
-    private static final boolean DEBUG = true;
-
-    private static final String TAG = "VirtualViewDelegate";
-
-    /**
-     * Auto-fills a virtual view with the {@code value}.
-     *
-     * @param virtualId id identifying the virtual node inside the custom view.
-     * @param value value to be auto-filled.
-     */
-    public abstract void autoFill(int virtualId, AutoFillValue value);
-
-    /**
-     * Callback used to notify the AutoFill Framework of changes made on the view hierarchy while
-     * an {@link android.app.Activity} is being auto filled.
-     */
-    public abstract static class Callback {
-
-        /**
-         * Sent when the auto-fill bar for a child must be updated.
-         *
-         * See {@link AutoFillManager#updateAutoFillInput(View, int, android.graphics.Rect, int)}
-         * for more details.
-         */
-        // TODO(b/33197203): do we really need it, or should the parent view just call
-        // AutoFillManager.updateAutoFillInput() directly?
-        public void onAutoFillInputUpdated(int virtualId, @Nullable Rect boundaries, int flags) {
-            if (DEBUG) {
-                Log.v(TAG, "onAutoFillInputUpdated(): virtualId=" + virtualId + ", boundaries="
-                        + boundaries + ", flags=" + flags);
-            }
-        }
-
-        /**
-         * Sent when the value of a node was changed.
-         *
-         * <p>This method should only be called when the change was not caused by the AutoFill
-         * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
-         * but by external causes (for example, when the user changed the value through the view's
-         * UI).
-         *
-         * @param virtualId id of the node whose value changed.
-         */
-        public void onValueChanged(int virtualId) {
-            if (DEBUG) Log.d(TAG, "onValueChanged() for" + virtualId);
-        }
-
-        /**
-         * Sent when nodes were removed (or had their ids changed) after the hierarchy has been
-         * committed to
-         * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}.
-         *
-         * <p>For example, when the view is rendering an {@code HTML} page, it should call this
-         * method when:
-         * <ul>
-         * <li>User navigated to another page and some (or all) nodes are gone.
-         * <li>The page's {@code DOM} was changed by {@code JavaScript} and some nodes moved (and
-         * are now identified by different ids).
-         * </ul>
-         *
-         * @param virtualIds id of the nodes that were removed.
-         */
-        public void onNodeRemoved(int... virtualIds) {
-            if (DEBUG) Log.d(TAG, "onNodeRemoved(): " + virtualIds);
-        }
-    }
-}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 71c1d62..57f9895 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.inputmethodservice.InputMethodService;
 import android.os.Bundle;
 import android.os.Handler;
 import android.view.KeyCharacterMap;
@@ -751,13 +752,19 @@
     public boolean clearMetaKeyStates(int states);
 
     /**
-     * Called by the IME to tell the client when it switches between
-     * fullscreen and normal modes. This will normally be called for
-     * you by the standard implementation of
-     * {@link android.inputmethodservice.InputMethodService}.
+     * Called back when the connected IME switches between fullscreen and normal modes.
      *
-     * @return true on success, false if the input connection is no longer
-     * valid.
+     * <p>Note: On {@link android.os.Build.VERSION_CODES#O} and later devices, input methods are no
+     * longer allowed to directly call this method at any time. To signal this event in the target
+     * application, input methods should always call
+     * {@link InputMethodService#updateFullscreenMode()} instead. This approach should work on API
+     * {@link android.os.Build.VERSION_CODES#N_MR1} and prior devices.</p>
+     *
+     * @return For editor authors, the return value will always be ignored. For IME authors, this
+     *         always returns {@code true} on {@link android.os.Build.VERSION_CODES#N_MR1} and prior
+     *         devices and {@code false} on {@link android.os.Build.VERSION_CODES#O} and later
+     *         devices.
+     * @see InputMethodManager#isFullscreenMode()
      */
     public boolean reportFullscreenMode(boolean enabled);
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2e99092..13abe7c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -34,7 +34,6 @@
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.Trace;
-import android.text.TextUtils;
 import android.text.style.SuggestionSpan;
 import android.util.Log;
 import android.util.Pools.Pool;
@@ -396,6 +395,7 @@
     static final int MSG_TIMEOUT_INPUT_EVENT = 6;
     static final int MSG_FLUSH_INPUT_EVENT = 7;
     static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
+    static final int MSG_REPORT_FULLSCREEN_MODE = 10;
 
     class H extends Handler {
         H(Looper looper) {
@@ -476,12 +476,13 @@
                 }
                 case MSG_SET_ACTIVE: {
                     final boolean active = msg.arg1 != 0;
+                    final boolean fullscreen = msg.arg2 != 0;
                     if (DEBUG) {
                         Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
                     }
                     synchronized (mH) {
                         mActive = active;
-                        mFullscreenMode = false;
+                        mFullscreenMode = fullscreen;
                         if (!active) {
                             // Some other client has starting using the IME, so note
                             // that this happened and make sure our own editor's
@@ -523,6 +524,21 @@
                     synchronized (mH) {
                         mNextUserActionNotificationSequenceNumber = msg.arg1;
                     }
+                    return;
+                }
+                case MSG_REPORT_FULLSCREEN_MODE: {
+                    final boolean fullscreen = msg.arg1 != 0;
+                    InputConnection ic = null;
+                    synchronized (mH) {
+                        mFullscreenMode = fullscreen;
+                        if (mServedInputConnectionWrapper != null) {
+                            ic = mServedInputConnectionWrapper.getInputConnection();
+                        }
+                    }
+                    if (ic != null) {
+                        ic.reportFullscreenMode(fullscreen);
+                    }
+                    return;
                 }
             }
         }
@@ -557,18 +573,11 @@
         }
 
         @Override
-        protected void onReportFullscreenMode(boolean enabled, boolean calledInBackground) {
-            mParentInputMethodManager.onReportFullscreenMode(enabled, calledInBackground,
-                    getInputMethodId());
-        }
-
-        @Override
         public String toString() {
             return "ControlledInputConnectionWrapper{"
                     + "connection=" + getInputConnection()
                     + " finished=" + isFinished()
                     + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
-                    + " mInputMethodId=" + getInputMethodId()
                     + "}";
         }
     }
@@ -600,24 +609,31 @@
 
         @Override
         public void onBindMethod(InputBindResult res) {
-            mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
+            mH.obtainMessage(MSG_BIND, res).sendToTarget();
         }
 
         @Override
         public void onUnbindMethod(int sequence, @InputMethodClient.UnbindReason int unbindReason) {
-            mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, unbindReason));
+            mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget();
         }
 
         @Override
-        public void setActive(boolean active) {
-            mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
+        public void setActive(boolean active, boolean fullscreen) {
+            mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget();
         }
 
         @Override
         public void setUserActionNotificationSequenceNumber(int sequenceNumber) {
-            mH.sendMessage(mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
-                    sequenceNumber, 0));
+            mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER, sequenceNumber, 0)
+                    .sendToTarget();
         }
+
+        @Override
+        public void reportFullscreenMode(boolean fullscreen) {
+            mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0)
+                    .sendToTarget();
+        }
+
     };
 
     final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
@@ -731,16 +747,6 @@
     }
 
     /** @hide */
-    public void onReportFullscreenMode(boolean fullScreen, boolean calledInBackground,
-            String inputMethodId) {
-        synchronized (mH) {
-            if (!calledInBackground || TextUtils.equals(mCurId, inputMethodId)) {
-                mFullscreenMode = fullScreen;
-            }
-        }
-    }
-
-    /** @hide */
     public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
         try {
             mService.registerSuggestionSpansForNotification(spans);
@@ -770,6 +776,17 @@
     }
 
     /**
+     * @hide
+     */
+    public void reportFullscreenMode(IBinder token, boolean fullscreen) {
+        try {
+            mService.reportFullscreenMode(token, fullscreen);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Return true if the given view is the currently active view for the
      * input method.
      */
@@ -1274,9 +1291,6 @@
                         mCurId = res.id;
                         mNextUserActionNotificationSequenceNumber =
                                 res.userActionNotificationSequenceNumber;
-                        if (mServedInputConnectionWrapper != null) {
-                            mServedInputConnectionWrapper.setInputMethodId(mCurId);
-                        }
                     } else {
                         if (res.channel != null && res.channel != mCurChannel) {
                             res.channel.dispose();
@@ -2341,6 +2355,7 @@
                 + " mHasBeenInactive=" + mHasBeenInactive
                 + " mBindSequence=" + mBindSequence
                 + " mCurId=" + mCurId);
+        p.println("  mFullscreenMode=" + mFullscreenMode);
         p.println("  mCurMethod=" + mCurMethod);
         p.println("  mCurRootView=" + mCurRootView);
         p.println("  mServedView=" + mServedView);
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index a85dea9..a4e524f 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -41,6 +41,9 @@
 
     private static final String LOG_TAG = "TextClassificationManager";
 
+    private final Object mTextClassifierLock = new Object();
+    private final Object mLangIdLock = new Object();
+
     private final Context mContext;
     // TODO: Implement a way to close the file descriptor.
     private ParcelFileDescriptor mFd;
@@ -55,19 +58,21 @@
     /**
      * Returns the default text classifier.
      */
-    public synchronized TextClassifier getDefaultTextClassifier() {
-        if (mDefault == null) {
-            try {
-                mFd = ParcelFileDescriptor.open(
-                        new File("/etc/assistant/smart-selection.model"),
-                        ParcelFileDescriptor.MODE_READ_ONLY);
-                mDefault = new TextClassifierImpl(mContext, mFd);
-            } catch (FileNotFoundException e) {
-                Log.e(LOG_TAG, "Error accessing 'text classifier selection' model file.", e);
-                mDefault = TextClassifier.NO_OP;
+    public TextClassifier getDefaultTextClassifier() {
+        synchronized (mTextClassifierLock) {
+            if (mDefault == null) {
+                try {
+                    mFd = ParcelFileDescriptor.open(
+                            new File("/etc/assistant/smart-selection.model"),
+                            ParcelFileDescriptor.MODE_READ_ONLY);
+                    mDefault = new TextClassifierImpl(mContext, mFd);
+                } catch (FileNotFoundException e) {
+                    Log.e(LOG_TAG, "Error accessing 'text classifier selection' model file.", e);
+                    mDefault = TextClassifier.NO_OP;
+                }
             }
+            return mDefault;
         }
-        return mDefault;
     }
 
     /**
@@ -95,12 +100,14 @@
         return Collections.emptyList();
     }
 
-    private synchronized LangId getLanguageDetector() {
-        if (mLangId == null) {
-            // TODO: Use a file descriptor as soon as we start to depend on a model file
-            // for language detection.
-            mLangId = new LangId(0);
+    private LangId getLanguageDetector() {
+        synchronized (mLangIdLock) {
+            if (mLangId == null) {
+                // TODO: Use a file descriptor as soon as we start to depend on a model file
+                // for language detection.
+                mLangId = new LangId(0);
+            }
+            return mLangId;
         }
-        return mLangId;
     }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7838918..e2ff44c 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -60,6 +60,8 @@
 
     private static final String LOG_TAG = "TextClassifierImpl";
 
+    private final Object mSmartSelectionLock = new Object();
+
     private final Context mContext;
     private final ParcelFileDescriptor mFd;
     private SmartSelection mSmartSelection;
@@ -140,11 +142,13 @@
         return TextClassifier.NO_OP.getLinks(text, linkMask);
     }
 
-    private synchronized SmartSelection getSmartSelection() throws FileNotFoundException {
-        if (mSmartSelection == null) {
-            mSmartSelection = new SmartSelection(mFd.getFd());
+    private SmartSelection getSmartSelection() throws FileNotFoundException {
+        synchronized (mSmartSelectionLock) {
+            if (mSmartSelection == null) {
+                mSmartSelection = new SmartSelection(mFd.getFd());
+            }
+            return mSmartSelection;
         }
-        return mSmartSelection;
     }
 
     private TextClassificationResult createClassificationResult(String type, CharSequence text) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 47c4cf38..4c9a866 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2548,7 +2548,7 @@
     }
 
     private boolean isItemClickable(View view) {
-        return !view.hasFocusable(false);
+        return !view.hasExplicitFocusable();
     }
 
     /**
@@ -2824,7 +2824,7 @@
             final View v = getChildAt(mSelectedPosition - mFirstPosition);
 
             if (v != null) {
-                if (v.hasFocusable(false)) return;
+                if (v.hasExplicitFocusable()) return;
                 v.setPressed(true);
             }
             setPressed(true);
@@ -3428,7 +3428,7 @@
             if (mTouchMode == TOUCH_MODE_DOWN) {
                 mTouchMode = TOUCH_MODE_TAP;
                 final View child = getChildAt(mMotionPosition - mFirstPosition);
-                if (child != null && !child.hasFocusable(false)) {
+                if (child != null && !child.hasExplicitFocusable()) {
                     mLayoutMode = LAYOUT_NORMAL;
 
                     if (!mDataChanged) {
@@ -4005,7 +4005,7 @@
 
                 final float x = ev.getX();
                 final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;
-                if (inList && !child.hasFocusable(false)) {
+                if (inList && !child.hasExplicitFocusable()) {
                     if (mPerformClick == null) {
                         mPerformClick = new PerformClick();
                     }
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 9a39a17..51587a7 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -250,7 +250,7 @@
         mDefaultActivityButton = (FrameLayout) findViewById(R.id.default_activity_button);
         mDefaultActivityButton.setOnClickListener(mCallbacks);
         mDefaultActivityButton.setOnLongClickListener(mCallbacks);
-        mDefaultActivityButtonImage = mDefaultActivityButton.findViewById(R.id.image);
+        mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.image);
 
         final FrameLayout expandButton = (FrameLayout) findViewById(R.id.expand_activities_button);
         expandButton.setOnClickListener(mCallbacks);
@@ -282,7 +282,7 @@
         mExpandActivityOverflowButton = expandButton;
 
         mExpandActivityOverflowButtonImage =
-            expandButton.findViewById(R.id.image);
+            (ImageView) expandButton.findViewById(R.id.image);
         mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
 
         mAdapter = new ActivityChooserViewAdapter();
@@ -760,7 +760,7 @@
                         convertView = LayoutInflater.from(getContext()).inflate(
                                 R.layout.activity_chooser_view_list_item, parent, false);
                         convertView.setId(ITEM_VIEW_TYPE_FOOTER);
-                        TextView titleView = convertView.findViewById(R.id.title);
+                        TextView titleView = (TextView) convertView.findViewById(R.id.title);
                         titleView.setText(mContext.getString(
                                 R.string.activity_chooser_view_see_all));
                     }
@@ -772,11 +772,11 @@
                     }
                     PackageManager packageManager = mContext.getPackageManager();
                     // Set the icon
-                    ImageView iconView = convertView.findViewById(R.id.icon);
+                    ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
                     ResolveInfo activity = (ResolveInfo) getItem(position);
                     iconView.setImageDrawable(activity.loadIcon(packageManager));
                     // Set the title.
-                    TextView titleView = convertView.findViewById(R.id.title);
+                    TextView titleView = (TextView) convertView.findViewById(R.id.title);
                     titleView.setText(activity.loadLabel(packageManager));
                     // Highlight the default.
                     if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 06d4868..68e6809 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -451,7 +451,7 @@
 
     private View getPermissionsView(int which, boolean showRevokeUI) {
         LinearLayout permsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
-        LinearLayout displayList = permsView.findViewById(R.id.perms_list);
+        LinearLayout displayList = (LinearLayout) permsView.findViewById(R.id.perms_list);
         View noPermsView = permsView.findViewById(R.id.no_permissions);
 
         displayPermissions(mPermGroupsList, displayList, which, showRevokeUI);
@@ -517,8 +517,8 @@
             CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) {
         View permView = inflater.inflate(R.layout.app_permission_item_old, null);
 
-        TextView permGrpView = permView.findViewById(R.id.permission_group);
-        TextView permDescView = permView.findViewById(R.id.permission_list);
+        TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
+        TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
 
         ImageView imgView = (ImageView)permView.findViewById(R.id.perm_icon);
         imgView.setImageDrawable(icon);
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 81f0d3d..bbc50da 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -388,7 +388,7 @@
                 text = (TextView) view;
             } else {
                 //  Otherwise, find the TextView field within the layout
-                text = view.findViewById(mFieldId);
+                text = (TextView) view.findViewById(mFieldId);
 
                 if (text == null) {
                     throw new RuntimeException("Failed to find view with ID "
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
index 1b899db..557d411 100644
--- a/core/java/android/widget/CalendarViewLegacyDelegate.java
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -316,9 +316,9 @@
         View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
         mDelegator.addView(content);
 
-        mListView = mDelegator.findViewById(R.id.list);
-        mDayNamesHeader = content.findViewById(R.id.day_names);
-        mMonthName = content.findViewById(R.id.month_name);
+        mListView = (ListView) mDelegator.findViewById(R.id.list);
+        mDayNamesHeader = (ViewGroup) content.findViewById(R.id.day_names);
+        mMonthName = (TextView) content.findViewById(R.id.month_name);
 
         setUpHeader();
         setUpListView();
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 500f381..6f687fe 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -32,7 +32,6 @@
 import android.view.SoundEffectConstants;
 import android.view.ViewDebug;
 import android.view.ViewHierarchyEncoder;
-import android.view.ViewStructure;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.autofill.AutoFillType;
@@ -562,17 +561,14 @@
         stream.addProperty("checked", isChecked());
     }
 
-    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
 
-    @Override
-    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
-        super.onProvideAutoFillStructure(structure, flags);
-        structure.setAutoFillValue(AutoFillValue.forToggle(isChecked()));
-        // TODO(b/33197203): add unit/CTS tests for auto-fill methods
-    }
+    // TODO(b/33197203): override onProvideAutoFillStructure and add a change listener
 
     @Override
     public void autoFill(AutoFillValue value) {
+        if (!isEnabled()) return;
+
         setChecked(value.getToggleValue());
     }
 
@@ -580,4 +576,9 @@
     public AutoFillType getAutoFillType() {
         return AutoFillType.forToggle();
     }
+
+    @Override
+    public AutoFillValue getAutoFillValue() {
+        return isEnabled() ? null : AutoFillValue.forToggle(isChecked());
+    }
 }
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 907250a..f712685 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -115,10 +115,10 @@
         mDelegator.addView(mContainer);
 
         // Set up header views.
-        final ViewGroup header = mContainer.findViewById(R.id.date_picker_header);
-        mHeaderYear = header.findViewById(R.id.date_picker_header_year);
+        final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header);
+        mHeaderYear = (TextView) header.findViewById(R.id.date_picker_header_year);
         mHeaderYear.setOnClickListener(mOnHeaderClickListener);
-        mHeaderMonthDay = header.findViewById(R.id.date_picker_header_date);
+        mHeaderMonthDay = (TextView) header.findViewById(R.id.date_picker_header_date);
         mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener);
 
         // For the sake of backwards compatibility, attempt to extract the text
@@ -154,10 +154,10 @@
         a.recycle();
 
         // Set up picker container.
-        mAnimator = mContainer.findViewById(R.id.animator);
+        mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator);
 
         // Set up day picker view.
-        mDayPickerView = mAnimator.findViewById(R.id.date_picker_day_picker);
+        mDayPickerView = (DayPickerView) mAnimator.findViewById(R.id.date_picker_day_picker);
         mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
         mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
         mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
@@ -165,7 +165,7 @@
         mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
 
         // Set up year picker view.
-        mYearPickerView = mAnimator.findViewById(R.id.date_picker_year_picker);
+        mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker);
         mYearPickerView.setRange(mMinDate, mMaxDate);
         mYearPickerView.setYear(mCurrentDate.get(Calendar.YEAR));
         mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index 63621e1..8d5bf8f 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -225,7 +225,7 @@
     public Object instantiateItem(ViewGroup container, int position) {
         final View itemView = mInflater.inflate(mLayoutResId, container, false);
 
-        final SimpleMonthView v = itemView.findViewById(mCalendarViewId);
+        final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId);
         v.setOnDayClickListener(mOnDayClickListener);
         v.setMonthTextAppearance(mMonthTextAppearance);
         v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index 058baa6..a27e022 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -21,10 +21,10 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import com.android.internal.util.Predicate;
 import com.android.internal.widget.ViewPager;
 
 import java.util.ArrayList;
+import java.util.function.Predicate;
 
 /**
  * This displays a list of months in a calendar format with selectable days.
@@ -137,10 +137,9 @@
     }
 
     @Override
-    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
-            View childToSkip) {
-        if (predicate.apply(this)) {
-            return (T) this;
+    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+        if (predicate.test(this)) {
+            return this;
         }
 
         // Always try the selected view first.
@@ -149,7 +148,7 @@
         if (current != childToSkip && current != null) {
             final View v = current.findViewByPredicate(predicate);
             if (v != null) {
-                return (T) v;
+                return v;
             }
         }
 
@@ -161,7 +160,7 @@
                 final View v = child.findViewByPredicate(predicate);
 
                 if (v != null) {
-                    return (T) v;
+                    return v;
                 }
             }
         }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index a2cb491..45b5570 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -95,7 +95,6 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewParent;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -107,7 +106,6 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.view.textclassifier.TextClassificationResult;
-import android.view.textclassifier.TextSelection;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.TextView.Drawables;
 import android.widget.TextView.OnEditorActionListener;
@@ -140,7 +138,6 @@
     private static final boolean DEBUG_UNDO = false;
 
     static final int BLINK = 500;
-    private static final float[] TEMP_POSITION = new float[2];
     private static final int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
     private static final float LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS = 0.5f;
     private static final int UNSET_X_VALUE = -1;
@@ -152,10 +149,10 @@
     private static final int MENU_ITEM_ORDER_ASSIST = 1;
     private static final int MENU_ITEM_ORDER_UNDO = 2;
     private static final int MENU_ITEM_ORDER_REDO = 3;
-    private static final int MENU_ITEM_ORDER_SHARE = 4;
-    private static final int MENU_ITEM_ORDER_CUT = 5;
-    private static final int MENU_ITEM_ORDER_COPY = 6;
-    private static final int MENU_ITEM_ORDER_PASTE = 7;
+    private static final int MENU_ITEM_ORDER_CUT = 4;
+    private static final int MENU_ITEM_ORDER_COPY = 5;
+    private static final int MENU_ITEM_ORDER_PASTE = 6;
+    private static final int MENU_ITEM_ORDER_SHARE = 7;
     private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 8;
     private static final int MENU_ITEM_ORDER_SELECT_ALL = 9;
     private static final int MENU_ITEM_ORDER_REPLACE = 10;
@@ -171,7 +168,7 @@
     private InsertionPointCursorController mInsertionPointCursorController;
     SelectionModifierCursorController mSelectionModifierCursorController;
     // Action mode used when text is selected or when actions on an insertion cursor are triggered.
-    ActionMode mTextActionMode;
+    private ActionMode mTextActionMode;
     private boolean mInsertionControllerEnabled;
     private boolean mSelectionControllerEnabled;
 
@@ -238,7 +235,7 @@
     private boolean mPreserveSelection;
     private boolean mRestartActionModeOnNextRefresh;
 
-    private TextClassificationResult mTextClassificationResult;
+    private SelectionActionModeHelper mSelectionActionModeHelper;
 
     boolean mIsBeingLongClicked;
 
@@ -294,7 +291,7 @@
 
     private Rect mTempRect;
 
-    private TextView mTextView;
+    private final TextView mTextView;
 
     final ProcessTextIntentActionsHandler mProcessTextIntentActionsHandler;
 
@@ -1032,46 +1029,6 @@
                 boolean parentPositionChanged, boolean parentScrolled);
     }
 
-    private boolean isPositionVisible(final float positionX, final float positionY) {
-        synchronized (TEMP_POSITION) {
-            final float[] position = TEMP_POSITION;
-            position[0] = positionX;
-            position[1] = positionY;
-            View view = mTextView;
-
-            while (view != null) {
-                if (view != mTextView) {
-                    // Local scroll is already taken into account in positionX/Y
-                    position[0] -= view.getScrollX();
-                    position[1] -= view.getScrollY();
-                }
-
-                if (position[0] < 0 || position[1] < 0 || position[0] > view.getWidth()
-                        || position[1] > view.getHeight()) {
-                    return false;
-                }
-
-                if (!view.getMatrix().isIdentity()) {
-                    view.getMatrix().mapPoints(position);
-                }
-
-                position[0] += view.getLeft();
-                position[1] += view.getTop();
-
-                final ViewParent parent = view.getParent();
-                if (parent instanceof View) {
-                    view = (View) parent;
-                } else {
-                    // We've reached the ViewRoot, stop iterating
-                    view = null;
-                }
-            }
-        }
-
-        // We've been able to walk up the view hierarchy and the position was never clipped
-        return true;
-    }
-
     private boolean isOffsetVisible(int offset) {
         Layout layout = mTextView.getLayout();
         if (layout == null) return false;
@@ -1079,7 +1036,8 @@
         final int line = layout.getLineForOffset(offset);
         final int lineBottom = layout.getLineBottom(line);
         final int primaryHorizontal = (int) layout.getPrimaryHorizontal(offset);
-        return isPositionVisible(primaryHorizontal + mTextView.viewportToContentHorizontalOffset(),
+        return mTextView.isPositionVisible(
+                primaryHorizontal + mTextView.viewportToContentHorizontalOffset(),
                 lineBottom + mTextView.viewportToContentVerticalOffset());
     }
 
@@ -1891,7 +1849,7 @@
             mInsertionPointCursorController.invalidateHandle();
         }
         if (mTextActionMode != null) {
-            invalidateActionMode(getTextClassifierInfo(false));
+            invalidateActionModeAsync();
         }
     }
 
@@ -1984,12 +1942,12 @@
                 if (mRestartActionModeOnNextRefresh) {
                     // To avoid distraction, newly start action mode only when selection action
                     // mode is being restarted.
-                    startSelectionActionMode(null);
+                    startSelectionActionMode();
                 }
             } else if (selectionController == null || !selectionController.isActive()) {
                 // Insertion action mode is active. Avoid dismissing the selection.
                 stopTextActionModeWithPreservingSelection();
-                startSelectionActionMode(null);
+                startSelectionActionMode();
             } else {
                 mTextActionMode.invalidateContentRect();
             }
@@ -2026,55 +1984,46 @@
         }
     }
 
+    @NonNull
+    TextView getTextView() {
+        return mTextView;
+    }
+
+    @Nullable
+    ActionMode getTextActionMode() {
+        return mTextActionMode;
+    }
+
+    void setRestartActionModeOnNextRefresh(boolean value) {
+        mRestartActionModeOnNextRefresh = value;
+    }
+
     /**
-     * Starts a Selection Action Mode with the current selection and ensures the selection handles
-     * are shown if there is a selection. This should be used when the mode is started from a
-     * non-touch event.
-     *
-     * @return true if the selection mode was actually started.
+     * Asynchronously starts a selection action mode using the TextClassifier.
      */
-    boolean startSelectionActionMode(@Nullable TextClassificationResult textClassificationResult) {
-        mTextClassificationResult = textClassificationResult;
-        boolean selectionStarted = startSelectionActionModeInternal();
-        if (selectionStarted) {
-            getSelectionController().show();
+    void startSelectionActionModeAsync() {
+        getSelectionActionModeHelper().startActionModeAsync();
+    }
+
+    /**
+     * Synchronously starts a selection action mode without the TextClassifier.
+     */
+    void startSelectionActionMode() {
+        getSelectionActionModeHelper().startActionMode();
+    }
+
+    /**
+     * Asynchronously invalidates an action mode using the TextClassifier.
+     */
+    private void invalidateActionModeAsync() {
+        getSelectionActionModeHelper().invalidateActionModeAsync();
+    }
+
+    private SelectionActionModeHelper getSelectionActionModeHelper() {
+        if (mSelectionActionModeHelper == null) {
+            mSelectionActionModeHelper = new SelectionActionModeHelper(this);
         }
-        mRestartActionModeOnNextRefresh = false;
-        return selectionStarted;
-    }
-
-    private boolean startSelectionActionModeWithTextAssistant() {
-        return startSelectionActionMode(getTextClassifierInfo(true));
-    }
-
-    private void invalidateActionMode(TextClassificationResult textClassificationResult) {
-        mTextClassificationResult = textClassificationResult;
-        mTextActionMode.invalidate();
-    }
-
-    // TODO: Make this a non-blocking call.
-    private TextClassificationResult getTextClassifierInfo(boolean updateSelection) {
-        // TODO: Trim the text so that only text necessary to provide context of the selected
-        // text is sent to the assistant.
-        final int trimStartIndex = 0;
-        final int trimEndIndex = mTextView.getText().length();
-        CharSequence trimmedText =
-                mTextView.getText().subSequence(trimStartIndex, trimEndIndex);
-        int startIndex = mTextView.getSelectionStart() - trimStartIndex;
-        int endIndex = mTextView.getSelectionEnd() - trimStartIndex;
-
-        if (updateSelection) {
-            TextSelection textSelection = mTextView.getTextClassifier()
-                    .suggestSelection(trimmedText, startIndex, endIndex);
-            startIndex = Math.max(0, textSelection.getSelectionStartIndex() + trimStartIndex);
-            endIndex = Math.min(mTextView.getText().length(),
-                    textSelection.getSelectionEndIndex() + trimStartIndex);
-            Selection.setSelection((Spannable) mTextView.getText(), startIndex, endIndex);
-            return getTextClassifierInfo(false);
-        }
-
-        return mTextView.getTextClassifier()
-                .getTextClassificationResult(trimmedText, startIndex, endIndex);
+        return mSelectionActionModeHelper;
     }
 
     /**
@@ -2117,13 +2066,13 @@
         return true;
     }
 
-    private boolean startSelectionActionModeInternal() {
+    boolean startSelectionActionModeInternal() {
         if (extractedTextModeWillBeStarted()) {
             return false;
         }
         if (mTextActionMode != null) {
             // Text action mode is already started
-            invalidateActionMode(getTextClassifierInfo(false));
+            invalidateActionModeAsync();
             return false;
         }
 
@@ -2314,7 +2263,8 @@
         return mInsertionPointCursorController;
     }
 
-    private SelectionModifierCursorController getSelectionController() {
+    @Nullable
+    SelectionModifierCursorController getSelectionController() {
         if (!mSelectionControllerEnabled) {
             return null;
         }
@@ -3813,7 +3763,7 @@
             mode.setSubtitle(null);
             mode.setTitleOptionalHint(true);
             populateMenuWithItems(menu);
-            updateAssistMenuItem(menu, mTextClassificationResult);
+            updateAssistMenuItem(menu);
 
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
@@ -3881,7 +3831,7 @@
         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
             updateSelectAllItem(menu);
             updateReplaceItem(menu);
-            updateAssistMenuItem(menu, mTextClassificationResult);
+            updateAssistMenuItem(menu);
 
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
@@ -3914,9 +3864,10 @@
             }
         }
 
-        private void updateAssistMenuItem(
-                Menu menu, TextClassificationResult textClassificationResult) {
+        private void updateAssistMenuItem(Menu menu) {
             menu.removeItem(TextView.ID_ASSIST);
+            final TextClassificationResult textClassificationResult =
+                    getSelectionActionModeHelper().getTextClassificationResult();
             if (textClassificationResult != null) {
                 final Drawable icon = textClassificationResult.getIcon();
                 final CharSequence label = textClassificationResult.getLabel();
@@ -3925,7 +3876,7 @@
                 final Intent intent = textClassificationResult.getIntent();
                 if ((icon != null || !TextUtils.isEmpty(label))
                         && (onClickListener != null || intent != null)) {
-                    menu.add(Menu.NONE, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, label)
+                    menu.add(TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, label)
                             .setIcon(icon)
                             .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
                 }
@@ -3941,7 +3892,8 @@
             if (customCallback != null && customCallback.onActionItemClicked(mode, item)) {
                 return true;
             }
-            final TextClassificationResult textClassificationResult = mTextClassificationResult;
+            final TextClassificationResult textClassificationResult =
+                    getSelectionActionModeHelper().getTextClassificationResult();
             if (TextView.ID_ASSIST == item.getItemId() && textClassificationResult != null) {
                 final OnClickListener onClickListener =
                         textClassificationResult.getOnClickListener();
@@ -3964,8 +3916,8 @@
         @Override
         public void onDestroyActionMode(ActionMode mode) {
             // Clear mTextActionMode not to recursively destroy action mode by clearing selection.
+            getSelectionActionModeHelper().cancelAsyncTask();
             mTextActionMode = null;
-            mTextClassificationResult = null;
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
                 customCallback.onDestroyActionMode(mode);
@@ -4099,69 +4051,9 @@
                     final CharSequence composingText = text.subSequence(composingTextStart,
                             composingTextEnd);
                     builder.setComposingText(composingTextStart, composingText);
-
-                    final int minLine = layout.getLineForOffset(composingTextStart);
-                    final int maxLine = layout.getLineForOffset(composingTextEnd - 1);
-                    for (int line = minLine; line <= maxLine; ++line) {
-                        final int lineStart = layout.getLineStart(line);
-                        final int lineEnd = layout.getLineEnd(line);
-                        final int offsetStart = Math.max(lineStart, composingTextStart);
-                        final int offsetEnd = Math.min(lineEnd, composingTextEnd);
-                        final boolean ltrLine =
-                                layout.getParagraphDirection(line) == Layout.DIR_LEFT_TO_RIGHT;
-                        final float[] widths = new float[offsetEnd - offsetStart];
-                        layout.getPaint().getTextWidths(text, offsetStart, offsetEnd, widths);
-                        final float top = layout.getLineTop(line);
-                        final float bottom = layout.getLineBottom(line);
-                        for (int offset = offsetStart; offset < offsetEnd; ++offset) {
-                            final float charWidth = widths[offset - offsetStart];
-                            final boolean isRtl = layout.isRtlCharAt(offset);
-                            final float primary = layout.getPrimaryHorizontal(offset);
-                            final float secondary = layout.getSecondaryHorizontal(offset);
-                            // TODO: This doesn't work perfectly for text with custom styles and
-                            // TAB chars.
-                            final float left;
-                            final float right;
-                            if (ltrLine) {
-                                if (isRtl) {
-                                    left = secondary - charWidth;
-                                    right = secondary;
-                                } else {
-                                    left = primary;
-                                    right = primary + charWidth;
-                                }
-                            } else {
-                                if (!isRtl) {
-                                    left = secondary;
-                                    right = secondary + charWidth;
-                                } else {
-                                    left = primary - charWidth;
-                                    right = primary;
-                                }
-                            }
-                            // TODO: Check top-right and bottom-left as well.
-                            final float localLeft = left + viewportToContentHorizontalOffset;
-                            final float localRight = right + viewportToContentHorizontalOffset;
-                            final float localTop = top + viewportToContentVerticalOffset;
-                            final float localBottom = bottom + viewportToContentVerticalOffset;
-                            final boolean isTopLeftVisible = isPositionVisible(localLeft, localTop);
-                            final boolean isBottomRightVisible =
-                                    isPositionVisible(localRight, localBottom);
-                            int characterBoundsFlags = 0;
-                            if (isTopLeftVisible || isBottomRightVisible) {
-                                characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
-                            }
-                            if (!isTopLeftVisible || !isBottomRightVisible) {
-                                characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
-                            }
-                            if (isRtl) {
-                                characterBoundsFlags |= CursorAnchorInfo.FLAG_IS_RTL;
-                            }
-                            // Here offset is the index in Java chars.
-                            builder.addCharacterBounds(offset, localLeft, localTop, localRight,
-                                    localBottom, characterBoundsFlags);
-                        }
-                    }
+                    mTextView.populateCharacterBounds(builder, composingTextStart,
+                            composingTextEnd, viewportToContentHorizontalOffset,
+                            viewportToContentVerticalOffset);
                 }
             }
 
@@ -4177,10 +4069,10 @@
                         + viewportToContentVerticalOffset;
                 final float insertionMarkerBottom = layout.getLineBottom(line)
                         + viewportToContentVerticalOffset;
-                final boolean isTopVisible =
-                        isPositionVisible(insertionMarkerX, insertionMarkerTop);
-                final boolean isBottomVisible =
-                        isPositionVisible(insertionMarkerX, insertionMarkerBottom);
+                final boolean isTopVisible = mTextView
+                        .isPositionVisible(insertionMarkerX, insertionMarkerTop);
+                final boolean isBottomVisible = mTextView
+                        .isPositionVisible(insertionMarkerX, insertionMarkerBottom);
                 int insertionMarkerFlags = 0;
                 if (isTopVisible || isBottomVisible) {
                     insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
@@ -4388,7 +4280,8 @@
                 return false;
             }
 
-            return isPositionVisible(mPositionX + mHotspotX + getHorizontalOffset(), mPositionY);
+            return mTextView.isPositionVisible(
+                    mPositionX + mHotspotX + getHorizontalOffset(), mPositionY);
         }
 
         public abstract int getCurrentCursorOffset();
@@ -4783,7 +4676,7 @@
             }
             positionAtCursorOffset(offset, false);
             if (mTextActionMode != null) {
-                invalidateActionMode(getTextClassifierInfo(false));
+                invalidateActionModeAsync();
             }
         }
 
@@ -4867,7 +4760,7 @@
             }
             updateDrawable();
             if (mTextActionMode != null) {
-                invalidateActionMode(getTextClassifierInfo(false));
+                invalidateActionModeAsync();
             }
         }
 
@@ -5516,8 +5409,12 @@
 
                     if (mTextView.hasSelection()) {
                         // Do not invoke the text assistant if this was a drag selection.
-                        startSelectionActionMode(
-                                mHaventMovedEnoughToStartDrag ? getTextClassifierInfo(true) : null);
+                        if (mHaventMovedEnoughToStartDrag) {
+                            startSelectionActionModeAsync();
+                        } else {
+                            startSelectionActionMode();
+                        }
+
                     }
                     break;
             }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b7da04e..46e998a 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -49,12 +49,12 @@
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.R;
-import com.android.internal.util.Predicate;
 
 import com.google.android.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Predicate;
 
 /*
  * Implementation Notes:
@@ -3740,21 +3740,20 @@
      * @removed For internal use only. This should have been hidden.
      */
     @Override
-    protected <T extends View> T findViewTraversal(@IdRes int id) {
-        // First look in our children, then in any header and footer views that
-        // may be scrolled off.
-        View v = super.findViewTraversal(id);
+    protected View findViewTraversal(@IdRes int id) {
+        View v;
+        v = super.findViewTraversal(id);
         if (v == null) {
             v = findViewInHeadersOrFooters(mHeaderViewInfos, id);
             if (v != null) {
-                return (T) v;
+                return v;
             }
             v = findViewInHeadersOrFooters(mFooterViewInfos, id);
             if (v != null) {
-                return (T) v;
+                return v;
             }
         }
-        return (T) v;
+        return v;
     }
 
     View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) {
@@ -3783,22 +3782,21 @@
      * @removed For internal use only. This should have been hidden.
      */
     @Override
-    protected <T extends View> T findViewWithTagTraversal(Object tag) {
-        // First look in our children, then in any header and footer views that
-        // may be scrolled off.
-        View v = super.findViewWithTagTraversal(tag);
+    protected View findViewWithTagTraversal(Object tag) {
+        View v;
+        v = super.findViewWithTagTraversal(tag);
         if (v == null) {
             v = findViewWithTagInHeadersOrFooters(mHeaderViewInfos, tag);
             if (v != null) {
-                return (T) v;
+                return v;
             }
 
             v = findViewWithTagInHeadersOrFooters(mFooterViewInfos, tag);
             if (v != null) {
-                return (T) v;
+                return v;
             }
         }
-        return (T) v;
+        return v;
     }
 
     View findViewWithTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) {
@@ -3831,21 +3829,21 @@
      * @hide
      */
     @Override
-    protected <T extends View> T findViewByPredicateTraversal(
-            Predicate<View> predicate, View childToSkip) {
-        View v = super.findViewByPredicateTraversal(predicate, childToSkip);
+    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+        View v;
+        v = super.findViewByPredicateTraversal(predicate, childToSkip);
         if (v == null) {
             v = findViewByPredicateInHeadersOrFooters(mHeaderViewInfos, predicate, childToSkip);
             if (v != null) {
-                return (T) v;
+                return v;
             }
 
             v = findViewByPredicateInHeadersOrFooters(mFooterViewInfos, predicate, childToSkip);
             if (v != null) {
-                return (T) v;
+                return v;
             }
         }
-        return (T) v;
+        return v;
     }
 
     /**
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 8e04f1c..8008637 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -257,13 +257,13 @@
                 .getText(com.android.internal.R.string.lockscreen_transport_play_description);
         mPauseDescription = res
                 .getText(com.android.internal.R.string.lockscreen_transport_pause_description);
-        mPauseButton = v.findViewById(com.android.internal.R.id.pause);
+        mPauseButton = (ImageButton) v.findViewById(com.android.internal.R.id.pause);
         if (mPauseButton != null) {
             mPauseButton.requestFocus();
             mPauseButton.setOnClickListener(mPauseListener);
         }
 
-        mFfwdButton = v.findViewById(com.android.internal.R.id.ffwd);
+        mFfwdButton = (ImageButton) v.findViewById(com.android.internal.R.id.ffwd);
         if (mFfwdButton != null) {
             mFfwdButton.setOnClickListener(mFfwdListener);
             if (!mFromXml) {
@@ -271,7 +271,7 @@
             }
         }
 
-        mRewButton = v.findViewById(com.android.internal.R.id.rew);
+        mRewButton = (ImageButton) v.findViewById(com.android.internal.R.id.rew);
         if (mRewButton != null) {
             mRewButton.setOnClickListener(mRewListener);
             if (!mFromXml) {
@@ -280,16 +280,16 @@
         }
 
         // By default these are hidden. They will be enabled when setPrevNextListeners() is called
-        mNextButton = v.findViewById(com.android.internal.R.id.next);
+        mNextButton = (ImageButton) v.findViewById(com.android.internal.R.id.next);
         if (mNextButton != null && !mFromXml && !mListenersSet) {
             mNextButton.setVisibility(View.GONE);
         }
-        mPrevButton = v.findViewById(com.android.internal.R.id.prev);
+        mPrevButton = (ImageButton) v.findViewById(com.android.internal.R.id.prev);
         if (mPrevButton != null && !mFromXml && !mListenersSet) {
             mPrevButton.setVisibility(View.GONE);
         }
 
-        mProgress = v.findViewById(com.android.internal.R.id.mediacontroller_progress);
+        mProgress = (ProgressBar) v.findViewById(com.android.internal.R.id.mediacontroller_progress);
         if (mProgress != null) {
             if (mProgress instanceof SeekBar) {
                 SeekBar seeker = (SeekBar) mProgress;
@@ -298,8 +298,8 @@
             mProgress.setMax(1000);
         }
 
-        mEndTime = v.findViewById(com.android.internal.R.id.time);
-        mCurrentTime = v.findViewById(com.android.internal.R.id.time_current);
+        mEndTime = (TextView) v.findViewById(com.android.internal.R.id.time);
+        mCurrentTime = (TextView) v.findViewById(com.android.internal.R.id.time_current);
         mFormatBuilder = new StringBuilder();
         mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
 
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 5199b26..989927e 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -35,8 +35,8 @@
 import android.transition.Transition;
 import android.transition.Transition.EpicenterCallback;
 import android.transition.Transition.TransitionListener;
-import android.transition.Transition.TransitionListenerAdapter;
 import android.transition.TransitionInflater;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
 import android.transition.TransitionSet;
 import android.util.AttributeSet;
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 72dc1cc..8ba4694 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -24,7 +24,6 @@
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStructure;
 import android.view.autofill.AutoFillType;
 import android.view.autofill.AutoFillValue;
 
@@ -404,16 +403,14 @@
         }
     }
 
-    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
 
-    @Override
-    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
-        super.onProvideAutoFillStructure(structure, flags);
-        structure.setAutoFillValue(AutoFillValue.forList(getCheckedRadioButtonId()));
-    }
+    // TODO(b/33197203): override onProvideAutoFillStructure and add a change listener
 
     @Override
     public void autoFill(AutoFillValue value) {
+        if (!isEnabled()) return;
+
         final int index = value.getListValue();
         final View child = getChildAt(index);
         if (child == null) {
@@ -427,4 +424,9 @@
     public AutoFillType getAutoFillType() {
         return AutoFillType.forList();
     }
+
+    @Override
+    public AutoFillValue getAutoFillValue() {
+        return isEnabled() ? AutoFillValue.forList(getCheckedRadioButtonId()) : null;
+    }
 }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 5505f2f..359d04e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1578,7 +1578,7 @@
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
             final Context context = root.getContext();
-            final ViewGroup target = root.findViewById(viewId);
+            final ViewGroup target = (ViewGroup) root.findViewById(viewId);
             if (target == null) return;
             if (nestedViews != null) {
                 // Inflate nested views and add as children
@@ -1757,7 +1757,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = root.findViewById(viewId);
+            final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
             if (drawablesLoaded) {
                 if (isRelative) {
@@ -1857,7 +1857,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = root.findViewById(viewId);
+            final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
             target.setTextSize(units, size);
         }
@@ -2045,7 +2045,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = root.findViewById(viewId);
+            final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
             Drawable[] drawables = isRelative
                     ? target.getCompoundDrawablesRelative()
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
new file mode 100644
index 0000000..770d9ee
--- /dev/null
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -0,0 +1,288 @@
+/*
+ * 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 android.widget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UiThread;
+import android.annotation.WorkerThread;
+import android.os.AsyncTask;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.TextUtils;
+import android.view.ActionMode;
+import android.view.textclassifier.TextClassificationResult;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextSelection;
+import android.widget.Editor.SelectionModifierCursorController;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Helper class for starting selection action mode
+ * (synchronously without the TextClassifier, asynchronously with the TextClassifier).
+ */
+@UiThread
+final class SelectionActionModeHelper {
+
+    /**
+     * Maximum time (in milliseconds) to wait for a result before timing out.
+     */
+    // TODO: Consider making this a ViewConfiguration.
+    private static final int TIMEOUT_DURATION = 200;
+
+    private final Editor mEditor;
+    private final TextClassificationHelper mTextClassificationHelper;
+
+    private TextClassificationResult mTextClassificationResult;
+    private AsyncTask mTextClassificationAsyncTask;
+
+    SelectionActionModeHelper(@NonNull Editor editor) {
+        mEditor = Preconditions.checkNotNull(editor);
+        final TextView textView = mEditor.getTextView();
+        mTextClassificationHelper = new TextClassificationHelper(
+                textView.getTextClassifier(), textView.getText(),
+                textView.getSelectionStart(), textView.getSelectionEnd());
+    }
+
+    public void startActionModeAsync() {
+        cancelAsyncTask();
+        if (isNoOpTextClassifier()) {
+            // No need to make an async call for a no-op TextClassifier.
+            startActionMode(null);
+        } else {
+            resetTextClassificationHelper();
+            mTextClassificationAsyncTask = new TextClassificationAsyncTask(
+                    mEditor.getTextView(), TIMEOUT_DURATION,
+                    mTextClassificationHelper::suggestSelection, this::startActionMode)
+                    .execute();
+        }
+    }
+
+    public void startActionMode() {
+        startActionMode(null);
+    }
+
+    public void invalidateActionModeAsync() {
+        cancelAsyncTask();
+        if (isNoOpTextClassifier()) {
+            // No need to make an async call for a no-op TextClassifier.
+            invalidateActionMode(null);
+        } else {
+            resetTextClassificationHelper();
+            mTextClassificationAsyncTask = new TextClassificationAsyncTask(
+                    mEditor.getTextView(), TIMEOUT_DURATION,
+                    mTextClassificationHelper::classifyText, this::invalidateActionMode)
+                    .execute();
+        }
+    }
+
+    public void cancelAsyncTask() {
+        if (mTextClassificationAsyncTask != null) {
+            mTextClassificationAsyncTask.cancel(true);
+            mTextClassificationAsyncTask = null;
+        }
+        mTextClassificationResult = null;
+    }
+
+    @Nullable
+    public TextClassificationResult getTextClassificationResult() {
+        return mTextClassificationResult;
+    }
+
+    private boolean isNoOpTextClassifier() {
+        return mEditor.getTextView().getTextClassifier() == TextClassifier.NO_OP;
+    }
+
+    private void startActionMode(@Nullable SelectionResult result) {
+        final CharSequence text = mEditor.getTextView().getText();
+        if (result != null && text instanceof Spannable) {
+            Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
+            mTextClassificationResult = result.mResult;
+        } else {
+            mTextClassificationResult = null;
+        }
+        if (mEditor.startSelectionActionModeInternal()) {
+            final SelectionModifierCursorController controller = mEditor.getSelectionController();
+            if (controller != null) {
+                controller.show();
+            }
+        }
+        mEditor.setRestartActionModeOnNextRefresh(false);
+        mTextClassificationAsyncTask = null;
+    }
+
+    private void invalidateActionMode(@Nullable SelectionResult result) {
+        mTextClassificationResult = result != null ? result.mResult : null;
+        final ActionMode actionMode = mEditor.getTextActionMode();
+        if (actionMode != null) {
+            actionMode.invalidate();
+        }
+        mTextClassificationAsyncTask = null;
+    }
+
+    private void resetTextClassificationHelper() {
+        final TextView textView = mEditor.getTextView();
+        mTextClassificationHelper.reset(textView.getTextClassifier(), textView.getText(),
+                textView.getSelectionStart(), textView.getSelectionEnd());
+    }
+
+    /**
+     * AsyncTask for running a query on a background thread and returning the result on the
+     * UiThread. The AsyncTask times out after a specified time, returning a null result if the
+     * query has not yet returned.
+     */
+    private static final class TextClassificationAsyncTask
+            extends AsyncTask<Void, Void, SelectionResult> {
+
+        private final int mTimeOutDuration;
+        private final Supplier<SelectionResult> mSelectionResultSupplier;
+        private final Consumer<SelectionResult> mSelectionResultCallback;
+        private final TextView mTextView;
+        private final String mOriginalText;
+
+        /**
+         * @param textView the TextView
+         * @param timeOut time in milliseconds to timeout the query if it has not completed
+         * @param selectionResultSupplier fetches the selection results. Runs on a background thread
+         * @param selectionResultCallback receives the selection results. Runs on the UiThread
+         */
+        TextClassificationAsyncTask(
+                @NonNull TextView textView, int timeOut,
+                @NonNull Supplier<SelectionResult> selectionResultSupplier,
+                @NonNull Consumer<SelectionResult> selectionResultCallback) {
+            mTextView = Preconditions.checkNotNull(textView);
+            mTimeOutDuration = timeOut;
+            mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier);
+            mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback);
+            // Make a copy of the original text.
+            mOriginalText = mTextView.getText().toString();
+        }
+
+        @Override
+        @WorkerThread
+        protected SelectionResult doInBackground(Void... params) {
+            final Runnable onTimeOut = this::onTimeOut;
+            mTextView.postDelayed(onTimeOut, mTimeOutDuration);
+            final SelectionResult result = mSelectionResultSupplier.get();
+            mTextView.removeCallbacks(onTimeOut);
+            return result;
+        }
+
+        @Override
+        @UiThread
+        protected void onPostExecute(SelectionResult result) {
+            result = TextUtils.equals(mOriginalText, mTextView.getText()) ? result : null;
+            mSelectionResultCallback.accept(result);
+        }
+
+        private void onTimeOut() {
+            if (getStatus() == Status.RUNNING) {
+                onPostExecute(null);
+            }
+            cancel(true);
+        }
+    }
+
+    /**
+     * Helper class for querying the TextClassifier.
+     * It trims text so that only text necessary to provide context of the selected text is
+     * sent to the TextClassifier.
+     */
+    private static final class TextClassificationHelper {
+
+        private static final int TRIM_DELTA = 50;  // characters
+
+        private TextClassifier mTextClassifier;
+
+        /** The original TextView text. **/
+        private String mText;
+        /** Start index relative to mText. */
+        private int mSelectionStart;
+        /** End index relative to mText. */
+        private int mSelectionEnd;
+
+        /** Trimmed text starting from mTrimStart in mText. */
+        private CharSequence mTrimmedText;
+        /** Index indicating the start of mTrimmedText in mText. */
+        private int mTrimStart;
+        /** Start index relative to mTrimmedText */
+        private int mRelativeStart;
+        /** End index relative to mTrimmedText */
+        private int mRelativeEnd;
+
+        TextClassificationHelper(TextClassifier textClassifier,
+                CharSequence text, int selectionStart, int selectionEnd) {
+            reset(textClassifier, text, selectionStart, selectionEnd);
+        }
+
+        @UiThread
+        public void reset(TextClassifier textClassifier,
+                CharSequence text, int selectionStart, int selectionEnd) {
+            mTextClassifier = Preconditions.checkNotNull(textClassifier);
+            mText = Preconditions.checkNotNull(text).toString();
+            mSelectionStart = selectionStart;
+            mSelectionEnd = selectionEnd;
+        }
+
+        @WorkerThread
+        public SelectionResult classifyText() {
+            trimText();
+            return new SelectionResult(
+                    mSelectionStart,
+                    mSelectionEnd,
+                    mTextClassifier.getTextClassificationResult(
+                            mTrimmedText, mRelativeStart, mRelativeEnd));
+        }
+
+        @WorkerThread
+        public SelectionResult suggestSelection() {
+            trimText();
+            final TextSelection sel = mTextClassifier.suggestSelection(
+                    mTrimmedText, mRelativeStart, mRelativeEnd);
+            mSelectionStart = Math.max(0, sel.getSelectionStartIndex() + mTrimStart);
+            mSelectionEnd = Math.min(mText.length(), sel.getSelectionEndIndex() + mTrimStart);
+            return classifyText();
+        }
+
+        private void trimText() {
+            mTrimStart = Math.max(0, mSelectionStart - TRIM_DELTA);
+            final int referenceEnd = Math.min(mText.length(), mSelectionEnd + TRIM_DELTA);
+            mTrimmedText = mText.subSequence(mTrimStart, referenceEnd);
+            mRelativeStart = mSelectionStart - mTrimStart;
+            mRelativeEnd = mSelectionEnd - mTrimStart;
+        }
+    }
+
+    /**
+     * Selection result.
+     */
+    private static final class SelectionResult {
+        private final int mStart;
+        private final int mEnd;
+        private final TextClassificationResult mResult;
+
+        SelectionResult(int start, int end, TextClassificationResult result) {
+            mStart = start;
+            mEnd = end;
+            mResult = Preconditions.checkNotNull(result);
+        }
+    }
+}
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index fbb8993..f833d1b 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -286,7 +286,7 @@
         v.setTag(new ChildViewCache(v));
 
         // Set up icon.
-        final ImageView iconRefine = v.findViewById(R.id.edit_query);
+        final ImageView iconRefine = (ImageView) v.findViewById(R.id.edit_query);
         iconRefine.setImageResource(mCommitIconResId);
 
         return v;
@@ -304,11 +304,11 @@
         public final ImageView mIconRefine;
 
         public ChildViewCache(View v) {
-            mText1 = v.findViewById(com.android.internal.R.id.text1);
-            mText2 = v.findViewById(com.android.internal.R.id.text2);
-            mIcon1 = v.findViewById(com.android.internal.R.id.icon1);
-            mIcon2 = v.findViewById(com.android.internal.R.id.icon2);
-            mIconRefine = v.findViewById(com.android.internal.R.id.edit_query);
+            mText1 = (TextView) v.findViewById(com.android.internal.R.id.text1);
+            mText2 = (TextView) v.findViewById(com.android.internal.R.id.text2);
+            mIcon1 = (ImageView) v.findViewById(com.android.internal.R.id.icon1);
+            mIcon2 = (ImageView) v.findViewById(com.android.internal.R.id.icon2);
+            mIconRefine = (ImageView) v.findViewById(com.android.internal.R.id.edit_query);
         }
     }
 
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 7e2cadf..32418cd 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -619,7 +619,7 @@
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
-            final TextView tv = tabIndicator.findViewById(R.id.title);
+            final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
             tv.setText(mLabel);
 
             if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
@@ -653,8 +653,8 @@
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
-            final TextView tv = tabIndicator.findViewById(R.id.title);
-            final ImageView iconView = tabIndicator.findViewById(R.id.icon);
+            final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
+            final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
 
             // when icon is gone by default, we're in exclusive mode
             final boolean exclusive = iconView.getVisibility() == View.GONE;
diff --git a/core/java/android/widget/TextInputTimePickerView.java b/core/java/android/widget/TextInputTimePickerView.java
new file mode 100644
index 0000000..ef91576
--- /dev/null
+++ b/core/java/android/widget/TextInputTimePickerView.java
@@ -0,0 +1,249 @@
+/*
+ * 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 android.widget;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.util.MathUtils;
+import android.view.View;
+
+import com.android.internal.R;
+
+/**
+ * View to show text input based time picker with hour and minute fields and an optional AM/PM
+ * spinner.
+ *
+ * @hide
+ */
+public class TextInputTimePickerView extends RelativeLayout {
+    public static final int HOURS = 0;
+    public static final int MINUTES = 1;
+    public static final int AMPM = 2;
+
+    private static final int AM = 0;
+    private static final int PM = 1;
+
+    private final EditText mHourEditText;
+    private final EditText mMinuteEditText;
+    private final TextView mInputSeparatorView;
+    private final Spinner mAmPmSpinner;
+    private final TextView mErrorLabel;
+    private final TextView mHourLabel;
+    private final TextView mMinuteLabel;
+
+    private boolean mIs24Hour;
+    private boolean mHourFormatStartsAtZero;
+    private OnValueTypedListener mListener;
+
+    private boolean mErrorShowing;
+
+    interface OnValueTypedListener {
+        void onValueChanged(int inputType, int newValue);
+    }
+
+    public TextInputTimePickerView(Context context) {
+        this(context, null);
+    }
+
+    public TextInputTimePickerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TextInputTimePickerView(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    public TextInputTimePickerView(Context context, AttributeSet attrs, int defStyle,
+            int defStyleRes) {
+        super(context, attrs, defStyle, defStyleRes);
+
+        inflate(context, R.layout.time_picker_text_input_material, this);
+
+        mHourEditText = (EditText) findViewById(R.id.input_hour);
+        mMinuteEditText = (EditText) findViewById(R.id.input_minute);
+        mInputSeparatorView = (TextView) findViewById(R.id.input_separator);
+        mErrorLabel = (TextView) findViewById(R.id.label_error);
+        mHourLabel = (TextView) findViewById(R.id.label_hour);
+        mMinuteLabel = (TextView) findViewById(R.id.label_minute);
+
+        mHourEditText.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+            @Override
+            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+            @Override
+            public void afterTextChanged(Editable editable) {
+                parseAndSetHourInternal(editable.toString());
+            }
+        });
+
+        mMinuteEditText.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+            @Override
+            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
+
+            @Override
+            public void afterTextChanged(Editable editable) {
+                parseAndSetMinuteInternal(editable.toString());
+            }
+        });
+
+        mAmPmSpinner = (Spinner) findViewById(R.id.am_pm_spinner);
+        final String[] amPmStrings = TimePicker.getAmPmStrings(context);
+        ArrayAdapter<CharSequence> adapter =
+                new ArrayAdapter<CharSequence>(context, R.layout.simple_spinner_dropdown_item);
+        adapter.add(TimePickerClockDelegate.obtainVerbatim(amPmStrings[0]));
+        adapter.add(TimePickerClockDelegate.obtainVerbatim(amPmStrings[1]));
+        mAmPmSpinner.setAdapter(adapter);
+        mAmPmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> adapterView, View view, int position,
+                    long id) {
+                if (position == 0) {
+                    mListener.onValueChanged(AMPM, AM);
+                } else {
+                    mListener.onValueChanged(AMPM, PM);
+                }
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> adapterView) {}
+        });
+    }
+
+    void setListener(OnValueTypedListener listener) {
+        mListener = listener;
+    }
+
+    void setHourFormat(int maxCharLength) {
+        mHourEditText.setFilters(new InputFilter[] {
+                new InputFilter.LengthFilter(maxCharLength)});
+        mMinuteEditText.setFilters(new InputFilter[] {
+                new InputFilter.LengthFilter(maxCharLength)});
+    }
+
+    boolean validateInput() {
+        final boolean inputValid = parseAndSetHourInternal(mHourEditText.getText().toString())
+                && parseAndSetMinuteInternal(mMinuteEditText.getText().toString());
+        setError(!inputValid);
+        return inputValid;
+    }
+
+    void updateSeparator(String separatorText) {
+        mInputSeparatorView.setText(separatorText);
+    }
+
+    private void setError(boolean enabled) {
+        mErrorShowing = enabled;
+
+        mErrorLabel.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
+        mHourLabel.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
+        mMinuteLabel.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
+    }
+
+    /**
+     * Computes the display value and updates the text of the view.
+     * <p>
+     * This method should be called whenever the current value or display
+     * properties (leading zeroes, max digits) change.
+     */
+    void updateTextInputValues(int localizedHour, int minute, int amOrPm, boolean is24Hour,
+            boolean hourFormatStartsAtZero) {
+        final String format = "%d";
+
+        mIs24Hour = is24Hour;
+        mHourFormatStartsAtZero = hourFormatStartsAtZero;
+
+        mAmPmSpinner.setVisibility(is24Hour ? View.INVISIBLE : View.VISIBLE);
+
+        mHourEditText.setText(String.format(format, localizedHour));
+        mMinuteEditText.setText(String.format(format, minute));
+
+        if (amOrPm == AM) {
+            mAmPmSpinner.setSelection(0);
+        } else {
+            mAmPmSpinner.setSelection(1);
+        }
+
+        if (mErrorShowing) {
+            validateInput();
+        }
+    }
+
+    private boolean parseAndSetHourInternal(String input) {
+        try {
+            final int hour = Integer.parseInt(input);
+            if (!isValidLocalizedHour(hour)) {
+                final int minHour = mHourFormatStartsAtZero ? 0 : 1;
+                final int maxHour = mIs24Hour ? 23 : 11 + minHour;
+                mListener.onValueChanged(HOURS, getHourOfDayFromLocalizedHour(
+                        MathUtils.constrain(hour, minHour, maxHour)));
+                return false;
+            }
+            mListener.onValueChanged(HOURS, getHourOfDayFromLocalizedHour(hour));
+            return true;
+        } catch (NumberFormatException e) {
+            // Do nothing since we cannot parse the input.
+            return false;
+        }
+    }
+
+    private boolean parseAndSetMinuteInternal(String input) {
+        try {
+            final int minutes = Integer.parseInt(input);
+            if (minutes < 0 || minutes > 59) {
+                mListener.onValueChanged(MINUTES, MathUtils.constrain(minutes, 0, 59));
+                return false;
+            }
+            mListener.onValueChanged(MINUTES, minutes);
+            return true;
+        } catch (NumberFormatException e) {
+            // Do nothing since we cannot parse the input.
+            return false;
+        }
+    }
+
+    private boolean isValidLocalizedHour(int localizedHour) {
+        final int minHour = mHourFormatStartsAtZero ? 0 : 1;
+        final int maxHour = (mIs24Hour ? 23 : 11) + minHour;
+        return localizedHour >= minHour && localizedHour <= maxHour;
+    }
+
+    private int getHourOfDayFromLocalizedHour(int localizedHour) {
+        int hourOfDay = localizedHour;
+        if (mIs24Hour) {
+            if (!mHourFormatStartsAtZero && localizedHour == 24) {
+                hourOfDay = 0;
+            }
+        } else {
+            if (!mHourFormatStartsAtZero && localizedHour == 12) {
+                hourOfDay = 0;
+            }
+            if (mAmPmSpinner.getSelectedItemPosition() == 1) {
+                hourOfDay += 12;
+            }
+        }
+        return hourOfDay;
+    }
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4a8ec94..20e325c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,10 @@
 package android.widget;
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
+import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
+import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
+import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
 
 import android.R;
 import android.annotation.ColorInt;
@@ -109,6 +113,7 @@
 import android.text.style.UpdateAppearance;
 import android.text.util.Linkify;
 import android.util.AttributeSet;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -142,6 +147,7 @@
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
@@ -159,6 +165,8 @@
 import com.android.internal.util.FastMath;
 import com.android.internal.widget.EditableInputConnection;
 
+import libcore.util.EmptyArray;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -166,6 +174,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Locale;
 
 /**
@@ -262,12 +271,14 @@
  * @attr ref android.R.styleable#TextView_autoSizeMinTextSize
  * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
  * @attr ref android.R.styleable#TextView_autoSizeStepGranularity
+ * @attr ref android.R.styleable#TextView_autoSizeStepSizeSet
  */
 @RemoteView
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
     static final String LOG_TAG = "TextView";
     static final boolean DEBUG_EXTRACT = false;
     static final boolean DEBUG_AUTOFILL = false;
+    private static final float[] TEMP_POSITION = new float[2];
 
     // Enum for the "typeface" XML parameter.
     // TODO: How can we get this from the XML instead of hardcoding it here?
@@ -708,8 +719,13 @@
     private int mAutoSizeMinTextSizeInPx = 0;
     // Maximum text size for auto-sizing in pixels.
     private int mAutoSizeMaxTextSizeInPx = 0;
-    // Contains the sorted set of desired text sizes in pixels to pick from when auto-sizing text.
-    private int[] mAutoSizeTextSizesInPx;
+    // Contains a (specified or computed) distinct sorted set of text sizes in pixels to pick from
+    // when auto-sizing text.
+    private int[] mAutoSizeTextSizesInPx = EmptyArray.INT;
+    // Specifies whether auto-size should use the provided auto size steps set or if it should
+    // build the steps set using mAutoSizeMinTextSizeInPx, mAutoSizeMaxTextSizeInPx and
+    // mAutoSizeStepGranularityInPx.
+    private boolean mHasPredefinedAutoSizeSet = false;
 
     // Watcher used to notify changes to auto-fill manager.
     private AutoFillChangeWatcher mAutoFillChangeWatcher;
@@ -1301,8 +1317,19 @@
                 case com.android.internal.R.styleable.TextView_autoSizeMaxTextSize:
                     mAutoSizeMaxTextSizeInPx = a.getDimensionPixelSize(attr, 0);
                     break;
+
+                case com.android.internal.R.styleable.TextView_autoSizeStepSizeSet:
+                    final int autoSizeStepSizeArrayResId = a.getResourceId(attr, 0);
+                    if (autoSizeStepSizeArrayResId > 0) {
+                        final TypedArray autoSizePreDefTextSizes = a.getResources()
+                                .obtainTypedArray(autoSizeStepSizeArrayResId);
+                        setupAutoSizeStepSizeSet(autoSizePreDefTextSizes);
+                        autoSizePreDefTextSizes.recycle();
+                    }
+                    break;
             }
         }
+
         a.recycle();
 
         BufferType bufferType = BufferType.EDITABLE;
@@ -1599,7 +1626,7 @@
                         mAutoSizeMinTextSizeInPx = 0;
                         mAutoSizeMaxTextSizeInPx = 0;
                         mAutoSizeStepGranularityInPx = 0;
-                        mAutoSizeTextSizesInPx = null;
+                        mAutoSizeTextSizesInPx = EmptyArray.INT;
                         mNeedsAutoSizeText = false;
                     }
                     break;
@@ -1651,6 +1678,7 @@
         if (supportsAutoSizeText()) {
             mAutoSizeStepGranularityInPx = (int) TypedValue.applyDimension(
                     unit, size, getResources().getDisplayMetrics());
+            mHasPredefinedAutoSizeSet = false;
             setupAutoSizeTextXY();
         }
     }
@@ -1683,6 +1711,7 @@
         if (supportsAutoSizeText()) {
             mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
                     unit, size, getResources().getDisplayMetrics());
+            mHasPredefinedAutoSizeSet = false;
             setupAutoSizeTextXY();
         }
     }
@@ -1716,6 +1745,7 @@
         if (supportsAutoSizeText()) {
             mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
                     unit, size, getResources().getDisplayMetrics());
+            mHasPredefinedAutoSizeSet = false;
             setupAutoSizeTextXY();
         }
     }
@@ -1730,44 +1760,137 @@
         return mAutoSizeMaxTextSizeInPx;
     }
 
+    /**
+     * Sets a predefined array of sizes to be used when auto-sizing.
+     *
+     * <ul>Note:
+     * <li>when <code>presetSizes</code> is not empty then the auto-size algorithm will use the
+     * values provided here instead of calculating the values based on min, max and step size. Also
+     * the values will be de-duplicated, sorted and negative or zero values will be removed.
+     * <li>when <code>presetSizes</code> is empty then the auto-size algorithm will use the min, max
+     * and step size to build the set of available sizes to choose from. Note that if no values have
+     * been provided for any of min, max or step size then defaults will be used.
+     * </ul>
+     *
+     * @param presetSizes an {@code int} array of sizes in pixels
+     *
+     * @attr ref android.R.styleable#TextView_autoSizeStepSizeSet
+     *
+     * @see #getAutoSizeTextPresetSizes()
+     */
+    public void setAutoSizeTextPresetSizes(@NonNull int[] presetSizes) {
+        if (supportsAutoSizeText()) {
+            if (presetSizes.length > 0) {
+                mAutoSizeTextSizesInPx = cleanupAutoSizePredefinedSizes(presetSizes);
+                final int sizesLength = mAutoSizeTextSizesInPx.length;
+                mHasPredefinedAutoSizeSet = sizesLength > 0;
+                if (mHasPredefinedAutoSizeSet) {
+                    mAutoSizeMinTextSizeInPx = mAutoSizeTextSizesInPx[0];
+                    mAutoSizeMaxTextSizeInPx = mAutoSizeTextSizesInPx[sizesLength - 1];
+                    mAutoSizeStepGranularityInPx = 0;
+                }
+            } else {
+                mHasPredefinedAutoSizeSet = false;
+            }
+            setupAutoSizeTextXY();
+        }
+    }
+
+    /**
+     * @return the current auto-size {@code int} sizes array (in pixels).
+     *
+     * @see #setAutoSizeTextPresetSizes(int[])
+     * @see #setAutoSizeMinTextSize(int, float)
+     * @see #setAutoSizeMaxTextSize(int, float)
+     * @see #setAutoSizeStepGranularity(int, float)
+     */
+    public int[] getAutoSizeTextPresetSizes() {
+        return mAutoSizeTextSizesInPx;
+    }
+
+    private void setupAutoSizeStepSizeSet(TypedArray textSizes) {
+        final int textSizesLength = textSizes.length();
+        final int[] parsedSizes = new int[textSizesLength];
+
+        if (textSizesLength > 0) {
+            for (int i = 0; i < textSizesLength; i++) {
+                parsedSizes[i] = textSizes.getDimensionPixelSize(i, -1);
+            }
+            mAutoSizeTextSizesInPx = cleanupAutoSizePredefinedSizes(parsedSizes);
+            mHasPredefinedAutoSizeSet = mAutoSizeTextSizesInPx.length > 0;
+        }
+    }
+
+    // Returns distinct sorted positive values.
+    private int[] cleanupAutoSizePredefinedSizes(int[] predefinedValues) {
+        final int predefinedValuesLength = predefinedValues.length;
+        if (predefinedValuesLength == 0) {
+            return predefinedValues;
+        }
+        Arrays.sort(predefinedValues);
+
+        final IntArray uniqueValidSizes = new IntArray();
+        for (int i = 0; i < predefinedValuesLength; i++) {
+            final int currentPredefinedValue = predefinedValues[i];
+
+            if (currentPredefinedValue > 0
+                    && uniqueValidSizes.binarySearch(currentPredefinedValue) < 0) {
+                uniqueValidSizes.add(currentPredefinedValue);
+            }
+        }
+
+        return predefinedValuesLength == uniqueValidSizes.size()
+            ? predefinedValues
+            : uniqueValidSizes.toArray();
+    }
+
     private void setupAutoSizeTextXY() {
         if (supportsAutoSizeText() && mAutoSizeTextType == AUTO_SIZE_TEXT_TYPE_XY) {
-            // Set valid defaults.
-            if (mAutoSizeMinTextSizeInPx <= 0) {
-                mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
-                        TypedValue.COMPLEX_UNIT_SP,
-                        DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP,
-                        getResources().getDisplayMetrics());
-            }
+            // Calculate the sizes set based on minimum size, maximum size and step size if we do
+            // not have a predefined set of sizes or if the current sizes array is empty.
+            if (!mHasPredefinedAutoSizeSet || mAutoSizeTextSizesInPx.length == 0) {
+                // Set valid defaults.
+                if (mAutoSizeMinTextSizeInPx <= 0) {
+                    mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
+                            TypedValue.COMPLEX_UNIT_SP,
+                            DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP,
+                            getResources().getDisplayMetrics());
+                }
 
-            if (mAutoSizeMaxTextSizeInPx <= 0) {
-                mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
-                        TypedValue.COMPLEX_UNIT_SP,
-                        DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP,
-                        getResources().getDisplayMetrics());
-            }
+                if (mAutoSizeMaxTextSizeInPx <= 0) {
+                    mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
+                            TypedValue.COMPLEX_UNIT_SP,
+                            DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP,
+                            getResources().getDisplayMetrics());
+                }
 
-            if (mAutoSizeStepGranularityInPx <= 0) {
-                mAutoSizeStepGranularityInPx = DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX;
-            }
+                if (mAutoSizeStepGranularityInPx <= 0) {
+                    mAutoSizeStepGranularityInPx = DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX;
+                }
 
-            // Validate.
-            if (mAutoSizeMaxTextSizeInPx <= mAutoSizeMinTextSizeInPx) {
-                throw new IllegalStateException("Maximum auto-size text size ("
-                        + mAutoSizeMaxTextSizeInPx + "px) is less or equal to minimum auto-size "
-                        + "text size (" + mAutoSizeMinTextSizeInPx + "px)");
-            }
+                // Validate.
+                if (mAutoSizeMaxTextSizeInPx <= mAutoSizeMinTextSizeInPx) {
+                    throw new IllegalStateException("Maximum auto-size text size ("
+                            + mAutoSizeMaxTextSizeInPx
+                            + "px) is less or equal to minimum auto-size "
+                            + "text size (" + mAutoSizeMinTextSizeInPx + "px)");
+                }
 
-            // Calculate sizes to choose from based on the current auto-size configuration.
-            final int autoSizeValuesLength = (int) Math.ceil(
-                    (mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx)
-                            / mAutoSizeStepGranularityInPx);
-
-            mAutoSizeTextSizesInPx = new int[autoSizeValuesLength];
-            int sizeToAdd = mAutoSizeMinTextSizeInPx;
-            for (int i = 0; i < autoSizeValuesLength; i++) {
-                mAutoSizeTextSizesInPx[i] = sizeToAdd;
-                sizeToAdd += mAutoSizeStepGranularityInPx;
+                // Calculate sizes to choose from based on the current auto-size configuration.
+                int autoSizeValuesLength = (int) Math.ceil(
+                        (mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx)
+                                / (float) mAutoSizeStepGranularityInPx);
+                // Also reserve a slot for the max size if it fits.
+                if ((mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx)
+                        % mAutoSizeStepGranularityInPx == 0) {
+                    autoSizeValuesLength++;
+                }
+                mAutoSizeTextSizesInPx = new int[autoSizeValuesLength];
+                int sizeToAdd = mAutoSizeMinTextSizeInPx;
+                for (int i = 0; i < autoSizeValuesLength; i++) {
+                    mAutoSizeTextSizesInPx[i] = sizeToAdd;
+                    sizeToAdd += mAutoSizeStepGranularityInPx;
+                }
             }
 
             mNeedsAutoSizeText = true;
@@ -6635,7 +6758,7 @@
      */
     public boolean handleBackInTextActionModeIfNeeded(KeyEvent event) {
         // Do nothing unless mEditor is in text action mode.
-        if (mEditor == null || mEditor.mTextActionMode == null) {
+        if (mEditor == null || mEditor.getTextActionMode() == null) {
             return false;
         }
 
@@ -6819,7 +6942,7 @@
 
                 // Has to be done on key down (and not on key up) to correctly be intercepted.
             case KeyEvent.KEYCODE_BACK:
-                if (mEditor != null && mEditor.mTextActionMode != null) {
+                if (mEditor != null && mEditor.getTextActionMode() != null) {
                     stopTextActionMode();
                     return KEY_EVENT_HANDLED;
                 }
@@ -7815,16 +7938,6 @@
             scrollTo(0, 0);
         }
 
-        if (isAutoSizeEnabled()) {
-            if (mNeedsAutoSizeText) {
-                // Call auto-size after the width and height have been calculated.
-                autoSizeText();
-            }
-            // Always try to auto-size if enabled. Functions that do not want to trigger auto-sizing
-            // after the next measuring round should set this to false.
-            mNeedsAutoSizeText = true;
-        }
-
         setMeasuredDimension(width, height);
     }
 
@@ -7832,8 +7945,8 @@
      * Automatically computes and sets the text size.
      */
     private void autoSizeText() {
-        final int maxWidth = getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight();
-        final int maxHeight = getMeasuredHeight() - getTotalPaddingBottom() - getTotalPaddingTop();
+        final int maxWidth = getWidth() - getTotalPaddingLeft() - getTotalPaddingRight();
+        final int maxHeight = getHeight() - getExtendedPaddingBottom() - getExtendedPaddingTop();
 
         if (maxWidth <= 0 || maxHeight <= 0) {
             return;
@@ -7907,11 +8020,6 @@
                 return false;
             }
 
-            // Width overflow.
-            if (layout.getWidth() > availableSpace.right) {
-                return false;
-            }
-
             // Height overflow.
             if (layout.getHeight() > availableSpace.bottom) {
                 return false;
@@ -8079,6 +8187,16 @@
             mDeferScroll = -1;
             bringPointIntoView(Math.min(curs, mText.length()));
         }
+
+        if (isAutoSizeEnabled()) {
+            if (mNeedsAutoSizeText) {
+                // Call auto-size after the width and height have been calculated.
+                autoSizeText();
+            }
+            // Always try to auto-size if enabled. Functions that do not want to trigger auto-sizing
+            // after the next layout round should set this to false.
+            mNeedsAutoSizeText = true;
+        }
     }
 
     private boolean isShowingHint() {
@@ -9012,7 +9130,8 @@
 
                 if (mEditor != null) {
                     mEditor.refreshTextActionMode();
-                    if (!hasSelection() && mEditor.mTextActionMode == null && hasTransientState()) {
+                    if (!hasSelection()
+                            && mEditor.getTextActionMode() == null && hasTransientState()) {
                         // User generated selection has been removed.
                         setHasTransientState(false);
                     }
@@ -9639,7 +9758,7 @@
         return new GestureDetector(mContext,
                 new GestureDetector.SimpleOnGestureListener() {
                     @Override
-                    public boolean onSingleTapConfirmed(MotionEvent e) {
+                    public boolean onSingleTapUp(MotionEvent e) {
                         if (shouldUseClickableSpanOnClickGestureDetector()) {
                             ClickableSpan[] links = ((Spannable) mText).getSpans(
                                     getSelectionStart(), getSelectionEnd(),
@@ -9736,9 +9855,6 @@
                 // Simple case: this is a single line.
                 final CharSequence text = getText();
                 structure.setText(text, getSelectionStart(), getSelectionEnd());
-                if (forAutoFill && isTextEditable()) {
-                    structure.setAutoFillValue(AutoFillValue.forText(text));
-                }
             } else {
                 // Complex case: multi-line, could be scrolled or within a scroll container
                 // so some lines are not visible.
@@ -9795,9 +9911,6 @@
                     text = text.subSequence(expandedTopChar, expandedBottomChar);
                 }
                 structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
-                if (forAutoFill && isTextEditable()) {
-                    structure.setAutoFillValue(AutoFillValue.forText(text));
-                }
                 final int[] lineOffsets = new int[bottomLine - topLine + 1];
                 final int[] lineBaselines = new int[bottomLine - topLine + 1];
                 final int baselineOffset = getBaselineOffset();
@@ -9845,17 +9958,7 @@
         final CharSequence text = value.getTextValue();
 
         if (text != null && isTextEditable()) {
-            if (mAutoFillChangeWatcher == null || mAutoFillChangeWatcher.mOnAutoFill) {
-                setText(text, mBufferType, true, 0);
-            } else {
-                // Must disable listener first so it's not triggered.
-                mAutoFillChangeWatcher.mOnAutoFill = true;
-                try {
-                    setText(text, mBufferType, true, 0);
-                } finally {
-                    mAutoFillChangeWatcher.mOnAutoFill = false;
-                }
-            }
+            setText(text, mBufferType, true, 0);
         }
     }
 
@@ -9865,6 +9968,12 @@
         return isTextEditable() ? AutoFillType.forText(getInputType()) : null;
     }
 
+    @Override
+    @Nullable
+    public AutoFillValue getAutoFillValue() {
+        return isTextEditable() ? AutoFillValue.forText(getText()) : null;
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
@@ -9916,6 +10025,8 @@
                     | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
                     | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
             info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
+            info.setAvailableExtraData(
+                    Arrays.asList(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY));
         }
 
         if (isFocused()) {
@@ -9952,6 +10063,164 @@
         }
     }
 
+    @Override
+    public void addExtraDataToAccessibilityNodeInfo(
+            AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
+        if (extraDataKey.equals(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)) {
+            int positionInfoStartIndex = arguments.getInt(
+                    EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX, -1);
+            int positionInfoLength = arguments.getInt(
+                    EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH, -1);
+            if ((positionInfoLength <= 0) || (positionInfoStartIndex < 0)
+                    || (positionInfoStartIndex >= mText.length())) {
+                Log.e(LOG_TAG, "Invalid arguments for accessibility character locations");
+                return;
+            }
+            RectF[] boundingRects = new RectF[positionInfoLength];
+            final CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
+            populateCharacterBounds(builder, positionInfoStartIndex,
+                    positionInfoStartIndex + positionInfoLength,
+                    viewportToContentHorizontalOffset(), viewportToContentVerticalOffset());
+            CursorAnchorInfo cursorAnchorInfo = builder.setMatrix(null).build();
+            if (mTempRect == null) mTempRect = new Rect();
+            Rect viewBoundsInScreen = mTempRect;
+            info.getBoundsInScreen(viewBoundsInScreen);
+            for (int i = 0; i < positionInfoLength; i++) {
+                int flags = cursorAnchorInfo.getCharacterBoundsFlags(positionInfoStartIndex + i);
+                if ((flags & FLAG_HAS_VISIBLE_REGION) == FLAG_HAS_VISIBLE_REGION) {
+                    RectF bounds = cursorAnchorInfo
+                            .getCharacterBounds(positionInfoStartIndex + i);
+                    if (bounds != null) {
+                        bounds.offset(viewBoundsInScreen.left, viewBoundsInScreen.top);
+                        boundingRects[i] = bounds;
+                    }
+                }
+            }
+            info.getExtras().putParcelableArray(extraDataKey, boundingRects);
+        }
+    }
+
+    /**
+     * Populate requested character bounds in a {@link CursorAnchorInfo.Builder}
+     *
+     * @param builder The builder to populate
+     * @param startIndex The starting character index to populate
+     * @param endIndex The ending character index to populate
+     * @param viewportToContentHorizontalOffset The horizontal offset from the viewport to the
+     * content
+     * @param viewportToContentVerticalOffset The vertical offset from the viewport to the content
+     * @hide
+     */
+    public void populateCharacterBounds(CursorAnchorInfo.Builder builder,
+            int startIndex, int endIndex, float viewportToContentHorizontalOffset,
+            float viewportToContentVerticalOffset) {
+        final int minLine = mLayout.getLineForOffset(startIndex);
+        final int maxLine = mLayout.getLineForOffset(endIndex - 1);
+        for (int line = minLine; line <= maxLine; ++line) {
+            final int lineStart = mLayout.getLineStart(line);
+            final int lineEnd = mLayout.getLineEnd(line);
+            final int offsetStart = Math.max(lineStart, startIndex);
+            final int offsetEnd = Math.min(lineEnd, endIndex);
+            final boolean ltrLine =
+                    mLayout.getParagraphDirection(line) == Layout.DIR_LEFT_TO_RIGHT;
+            final float[] widths = new float[offsetEnd - offsetStart];
+            mLayout.getPaint().getTextWidths(mText, offsetStart, offsetEnd, widths);
+            final float top = mLayout.getLineTop(line);
+            final float bottom = mLayout.getLineBottom(line);
+            for (int offset = offsetStart; offset < offsetEnd; ++offset) {
+                final float charWidth = widths[offset - offsetStart];
+                final boolean isRtl = mLayout.isRtlCharAt(offset);
+                final float primary = mLayout.getPrimaryHorizontal(offset);
+                final float secondary = mLayout.getSecondaryHorizontal(offset);
+                // TODO: This doesn't work perfectly for text with custom styles and
+                // TAB chars.
+                final float left;
+                final float right;
+                if (ltrLine) {
+                    if (isRtl) {
+                        left = secondary - charWidth;
+                        right = secondary;
+                    } else {
+                        left = primary;
+                        right = primary + charWidth;
+                    }
+                } else {
+                    if (!isRtl) {
+                        left = secondary;
+                        right = secondary + charWidth;
+                    } else {
+                        left = primary - charWidth;
+                        right = primary;
+                    }
+                }
+                // TODO: Check top-right and bottom-left as well.
+                final float localLeft = left + viewportToContentHorizontalOffset;
+                final float localRight = right + viewportToContentHorizontalOffset;
+                final float localTop = top + viewportToContentVerticalOffset;
+                final float localBottom = bottom + viewportToContentVerticalOffset;
+                final boolean isTopLeftVisible = isPositionVisible(localLeft, localTop);
+                final boolean isBottomRightVisible =
+                        isPositionVisible(localRight, localBottom);
+                int characterBoundsFlags = 0;
+                if (isTopLeftVisible || isBottomRightVisible) {
+                    characterBoundsFlags |= FLAG_HAS_VISIBLE_REGION;
+                }
+                if (!isTopLeftVisible || !isBottomRightVisible) {
+                    characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+                }
+                if (isRtl) {
+                    characterBoundsFlags |= CursorAnchorInfo.FLAG_IS_RTL;
+                }
+                // Here offset is the index in Java chars.
+                builder.addCharacterBounds(offset, localLeft, localTop, localRight,
+                        localBottom, characterBoundsFlags);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isPositionVisible(final float positionX, final float positionY) {
+        synchronized (TEMP_POSITION) {
+            final float[] position = TEMP_POSITION;
+            position[0] = positionX;
+            position[1] = positionY;
+            View view = this;
+
+            while (view != null) {
+                if (view != this) {
+                    // Local scroll is already taken into account in positionX/Y
+                    position[0] -= view.getScrollX();
+                    position[1] -= view.getScrollY();
+                }
+
+                if (position[0] < 0 || position[1] < 0 || position[0] > view.getWidth()
+                        || position[1] > view.getHeight()) {
+                    return false;
+                }
+
+                if (!view.getMatrix().isIdentity()) {
+                    view.getMatrix().mapPoints(position);
+                }
+
+                position[0] += view.getLeft();
+                position[1] += view.getTop();
+
+                final ViewParent parent = view.getParent();
+                if (parent instanceof View) {
+                    view = (View) parent;
+                } else {
+                    // We've reached the ViewRoot, stop iterating
+                    view = null;
+                }
+            }
+        }
+
+        // We've been able to walk up the view hierarchy and the position was never clipped
+        return true;
+    }
+
     /**
      * Performs an accessibility action after it has been offered to the
      * delegate.
@@ -10009,7 +10278,7 @@
                         Selection.setSelection((Spannable) text, start, end);
                         // Make sure selection mode is engaged.
                         if (mEditor != null) {
-                            mEditor.startSelectionActionMode(null);
+                            mEditor.startSelectionActionModeAsync();
                         }
                         return true;
                     }
@@ -10724,14 +10993,6 @@
      * @hide
      */
     protected void viewClicked(InputMethodManager imm) {
-        final AutoFillManager afm = mContext.getSystemService(AutoFillManager.class);
-        if (afm != null) {
-            if (DEBUG_AUTOFILL) Log.v(LOG_TAG, "viewClicked(): id=" + getAccessibilityViewId());
-
-            // TODO(b/33197203): integrate with onFocus and/or move to view?
-            afm.updateAutoFillInput(this, AutoFillManager.FLAG_UPDATE_UI_SHOW);
-        }
-
         if (imm != null) {
             imm.viewClicked(this);
         }
@@ -11213,7 +11474,6 @@
     // TODO(b/33197203): implements SpanWatcher too?
     private final class AutoFillChangeWatcher implements TextWatcher {
 
-        private boolean mOnAutoFill;
         private final AutoFillManager mAfm = mContext.getSystemService(AutoFillManager.class);
 
         @Override
@@ -11226,18 +11486,11 @@
 
         @Override
         public void afterTextChanged(Editable s) {
-            if (mOnAutoFill) {
-                if (DEBUG_AUTOFILL) {
-                    Log.v(LOG_TAG, "AutoFillChangeWatcher.afterTextChanged() skipped during "
-                            + "autoFill(): s=" + s);
-                }
-                return;
-            }
             if (mAfm != null) {
                 if (DEBUG_AUTOFILL) {
                     Log.v(LOG_TAG, "AutoFillChangeWatcher.afterTextChanged(): s=" + s);
                 }
-                mAfm.onValueChanged(TextView.this, AutoFillValue.forText(s));
+                mAfm.valueChanged(TextView.this);
             }
         }
     }
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index e6cd798..9f38b04 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -278,6 +278,16 @@
         return mDelegate.getBaseline();
     }
 
+    /**
+     * Validates whether current input by the user is a valid time based on the locale. TimePicker
+     * will show an error message to the user if the time is not valid.
+     *
+     * @return {@code true} if the input is valid, {@code false} otherwise
+     */
+    public boolean validateInput() {
+        return mDelegate.validateInput();
+    }
+
     @Override
     protected Parcelable onSaveInstanceState() {
         Parcelable superState = super.onSaveInstanceState();
@@ -341,6 +351,8 @@
         void setIs24Hour(boolean is24Hour);
         boolean is24Hour();
 
+        boolean validateInput();
+
         void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
 
         void setEnabled(boolean enabled);
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 1d37a21..3a09063 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -16,12 +16,14 @@
 
 package android.widget;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.icu.text.DecimalFormatSymbols;
 import android.os.Parcelable;
 import android.text.SpannableStringBuilder;
 import android.text.format.DateFormat;
@@ -40,11 +42,14 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.widget.RadialTimePickerView.OnValueSelectedListener;
+import android.widget.TextInputTimePickerView.OnValueTypedListener;
 
 import com.android.internal.R;
 import com.android.internal.widget.NumericTextView;
 import com.android.internal.widget.NumericTextView.OnValueChangedListener;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Calendar;
 
 /**
@@ -58,6 +63,13 @@
      */
     private static final long DELAY_COMMIT_MILLIS = 2000;
 
+    @IntDef({FROM_EXTERNAL_API, FROM_RADIAL_PICKER, FROM_INPUT_PICKER})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ChangeSource {}
+    private static final int FROM_EXTERNAL_API = 0;
+    private static final int FROM_RADIAL_PICKER = 1;
+    private static final int FROM_INPUT_PICKER = 2;
+
     // Index used by RadialPickerLayout
     private static final int HOUR_INDEX = RadialTimePickerView.HOURS;
     private static final int MINUTE_INDEX = RadialTimePickerView.MINUTES;
@@ -78,6 +90,15 @@
     private final RadialTimePickerView mRadialTimePickerView;
     private final TextView mSeparatorView;
 
+    private boolean mRadialPickerModeEnabled = true;
+    private final ImageButton mRadialTimePickerModeButton;
+    private final String mRadialTimePickerModeEnabledDescription;
+    private final String mTextInputPickerModeEnabledDescription;
+    private final View mRadialTimePickerHeader;
+    private final View mTextInputPickerHeader;
+
+    private final TextInputTimePickerView mTextInputPickerView;
+
     private final Calendar mTempCalendar;
 
     // Accessibility strings.
@@ -116,8 +137,8 @@
         final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
                 R.layout.time_picker_material);
         final View mainView = inflater.inflate(layoutResourceId, delegator);
-        final View headerView = mainView.findViewById(R.id.time_header);
-        headerView.setOnTouchListener(new NearestTouchDelegate());
+        mRadialTimePickerHeader = mainView.findViewById(R.id.time_header);
+        mRadialTimePickerHeader.setOnTouchListener(new NearestTouchDelegate());
 
         // Set up hour/minute labels.
         mHourView = (NumericTextView) mainView.findViewById(R.id.hours);
@@ -170,6 +191,8 @@
             headerTextColor = a.getColorStateList(R.styleable.TimePicker_headerTextColor);
         }
 
+        mTextInputPickerHeader = mainView.findViewById(R.id.input_header);
+
         if (headerTextColor != null) {
             mHourView.setTextColor(headerTextColor);
             mSeparatorView.setTextColor(headerTextColor);
@@ -180,7 +203,10 @@
 
         // Set up header background, if available.
         if (a.hasValueOrEmpty(R.styleable.TimePicker_headerBackground)) {
-            headerView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
+            mRadialTimePickerHeader.setBackground(a.getDrawable(
+                    R.styleable.TimePicker_headerBackground));
+            mTextInputPickerHeader.setBackground(a.getDrawable(
+                    R.styleable.TimePicker_headerBackground));
         }
 
         a.recycle();
@@ -189,6 +215,22 @@
         mRadialTimePickerView.applyAttributes(attrs, defStyleAttr, defStyleRes);
         mRadialTimePickerView.setOnValueSelectedListener(mOnValueSelectedListener);
 
+        mTextInputPickerView = (TextInputTimePickerView) mainView.findViewById(R.id.input_mode);
+        mTextInputPickerView.setListener(mOnValueTypedListener);
+
+        mRadialTimePickerModeButton =
+                (ImageButton) mainView.findViewById(R.id.toggle_mode);
+        mRadialTimePickerModeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                toggleRadialPickerMode();
+            }
+        });
+        mRadialTimePickerModeEnabledDescription = context.getResources().getString(
+                R.string.time_picker_radial_mode_description);
+        mTextInputPickerModeEnabledDescription = context.getResources().getString(
+                R.string.time_picker_text_input_mode_description);
+
         mAllowAutoAdvance = true;
 
         updateHourFormat();
@@ -200,6 +242,34 @@
         initialize(currentHour, currentMinute, mIs24Hour, HOUR_INDEX);
     }
 
+    private void toggleRadialPickerMode() {
+        if (mRadialPickerModeEnabled) {
+            mRadialTimePickerView.setVisibility(View.GONE);
+            mRadialTimePickerHeader.setVisibility(View.GONE);
+            mTextInputPickerHeader.setVisibility(View.VISIBLE);
+            mTextInputPickerView.setVisibility(View.VISIBLE);
+            mRadialTimePickerModeButton.setImageResource(R.drawable.btn_event_material);
+            mRadialTimePickerModeButton.setContentDescription(
+                    mRadialTimePickerModeEnabledDescription);
+            mRadialPickerModeEnabled = false;
+        } else {
+            mRadialTimePickerView.setVisibility(View.VISIBLE);
+            mRadialTimePickerHeader.setVisibility(View.VISIBLE);
+            mTextInputPickerHeader.setVisibility(View.GONE);
+            mTextInputPickerView.setVisibility(View.GONE);
+            mRadialTimePickerModeButton.setImageResource(R.drawable.btn_keyboard_key_material);
+            mRadialTimePickerModeButton.setContentDescription(
+                    mTextInputPickerModeEnabledDescription);
+            updateTextInputPicker();
+            mRadialPickerModeEnabled = true;
+        }
+    }
+
+    @Override
+    public boolean validateInput() {
+        return mTextInputPickerView.validateInput();
+    }
+
     /**
      * Ensures that a TextView is wide enough to contain its text without
      * wrapping or clipping. Measures the specified view and sets the minimum
@@ -249,9 +319,16 @@
         final int maxHour = (mIs24Hour ? 23 : 11) + minHour;
         mHourView.setRange(minHour, maxHour);
         mHourView.setShowLeadingZeroes(mHourFormatShowLeadingZero);
+
+        final String[] digits = DecimalFormatSymbols.getInstance(mLocale).getDigitStrings();
+        int maxCharLength = 0;
+        for (int i = 0; i < 10; i++) {
+            maxCharLength = Math.max(maxCharLength, digits[i].length());
+        }
+        mTextInputPickerView.setHourFormat(maxCharLength * 2);
     }
 
-    private static final CharSequence obtainVerbatim(String text) {
+    static final CharSequence obtainVerbatim(String text) {
         return new SpannableStringBuilder().append(text,
                 new TtsSpan.VerbatimBuilder(text).build(), 0);
     }
@@ -333,10 +410,16 @@
         updateHeaderSeparator();
         updateHeaderMinute(mCurrentMinute, false);
         updateRadialPicker(index);
+        updateTextInputPicker();
 
         mDelegator.invalidate();
     }
 
+    private void updateTextInputPicker() {
+        mTextInputPickerView.updateTextInputValues(getLocalizedHour(mCurrentHour), mCurrentMinute,
+                mCurrentHour < 12 ? AM : PM, mIs24Hour, mHourFormatStartsAtZero);
+    }
+
     private void updateRadialPicker(int index) {
         mRadialTimePickerView.initialize(mCurrentHour, mCurrentMinute, mIs24Hour);
         setCurrentItemShowing(index, false, true);
@@ -381,10 +464,10 @@
      */
     @Override
     public void setHour(int hour) {
-        setHourInternal(hour, false, true);
+        setHourInternal(hour, FROM_EXTERNAL_API, true);
     }
 
-    private void setHourInternal(int hour, boolean isFromPicker, boolean announce) {
+    private void setHourInternal(int hour, @ChangeSource int source, boolean announce) {
         if (mCurrentHour == hour) {
             return;
         }
@@ -393,10 +476,13 @@
         updateHeaderHour(hour, announce);
         updateHeaderAmPm();
 
-        if (!isFromPicker) {
+        if (source != FROM_RADIAL_PICKER) {
             mRadialTimePickerView.setCurrentHour(hour);
             mRadialTimePickerView.setAmOrPm(hour < 12 ? AM : PM);
         }
+        if (source != FROM_INPUT_PICKER) {
+            updateTextInputPicker();
+        }
 
         mDelegator.invalidate();
         onTimeChanged();
@@ -424,10 +510,10 @@
      */
     @Override
     public void setMinute(int minute) {
-        setMinuteInternal(minute, false);
+        setMinuteInternal(minute, FROM_EXTERNAL_API);
     }
 
-    private void setMinuteInternal(int minute, boolean isFromPicker) {
+    private void setMinuteInternal(int minute, @ChangeSource int source) {
         if (mCurrentMinute == minute) {
             return;
         }
@@ -435,9 +521,12 @@
         mCurrentMinute = minute;
         updateHeaderMinute(minute, true);
 
-        if (!isFromPicker) {
+        if (source != FROM_RADIAL_PICKER) {
             mRadialTimePickerView.setCurrentMinute(minute);
         }
+        if (source != FROM_INPUT_PICKER) {
+            updateTextInputPicker();
+        }
 
         mDelegator.invalidate();
         onTimeChanged();
@@ -661,6 +750,7 @@
             separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
         }
         mSeparatorView.setText(separatorText);
+        mTextInputPickerView.updateSeparator(separatorText);
     }
 
     static private int lastIndexOfAny(String str, char[] any) {
@@ -712,7 +802,7 @@
 
         if (mRadialTimePickerView.setAmOrPm(amOrPm)) {
             mCurrentHour = getHour();
-
+            updateTextInputPicker();
             if (mOnTimeChangedListener != null) {
                 mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
             }
@@ -726,7 +816,7 @@
             switch (pickerType) {
                 case RadialTimePickerView.HOURS:
                     final boolean isTransition = mAllowAutoAdvance && autoAdvance;
-                    setHourInternal(newValue, true, !isTransition);
+                    setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
                     if (isTransition) {
                         setCurrentItemShowing(MINUTE_INDEX, true, false);
 
@@ -735,7 +825,7 @@
                     }
                     break;
                 case RadialTimePickerView.MINUTES:
-                    setMinuteInternal(newValue, true);
+                    setMinuteInternal(newValue, FROM_RADIAL_PICKER);
                     break;
             }
 
@@ -745,6 +835,23 @@
         }
     };
 
+    private final OnValueTypedListener mOnValueTypedListener = new OnValueTypedListener() {
+        @Override
+        public void onValueChanged(int pickerType, int newValue) {
+            switch (pickerType) {
+                case TextInputTimePickerView.HOURS:
+                    setHourInternal(newValue, FROM_INPUT_PICKER, false);
+                    break;
+                case TextInputTimePickerView.MINUTES:
+                    setMinuteInternal(newValue, FROM_INPUT_PICKER);
+                    break;
+                case TextInputTimePickerView.AMPM:
+                    setAmOrPm(newValue);
+                    break;
+            }
+        }
+    };
+
     /** Listener for keyboard interaction. */
     private final OnValueChangedListener mDigitEnteredListener = new OnValueChangedListener() {
         @Override
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 4634631..7ef54a5 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -86,7 +86,7 @@
         inflater.inflate(layoutResourceId, mDelegator, true);
 
         // hour
-        mHourSpinner = delegator.findViewById(R.id.hour);
+        mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
         mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
                 updateInputState();
@@ -100,17 +100,17 @@
                 onTimeChanged();
             }
         });
-        mHourSpinnerInput = mHourSpinner.findViewById(R.id.numberpicker_input);
+        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
         mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // divider (only for the new widget style)
-        mDivider = mDelegator.findViewById(R.id.divider);
+        mDivider = (TextView) mDelegator.findViewById(R.id.divider);
         if (mDivider != null) {
             setDividerText();
         }
 
         // minute
-        mMinuteSpinner = mDelegator.findViewById(R.id.minute);
+        mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
         mMinuteSpinner.setMinValue(0);
         mMinuteSpinner.setMaxValue(59);
         mMinuteSpinner.setOnLongPressUpdateInterval(100);
@@ -138,7 +138,7 @@
                 onTimeChanged();
             }
         });
-        mMinuteSpinnerInput = mMinuteSpinner.findViewById(R.id.numberpicker_input);
+        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
         mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // Get the localized am/pm strings and use them in the spinner.
@@ -173,13 +173,13 @@
                     onTimeChanged();
                 }
             });
-            mAmPmSpinnerInput = mAmPmSpinner.findViewById(R.id.numberpicker_input);
+            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
             mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
         }
 
         if (isAmPmAtStart()) {
             // Move the am/pm view to the beginning
-            ViewGroup amPmParent = delegator.findViewById(R.id.timePickerLayout);
+            ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
             amPmParent.removeView(amPmView);
             amPmParent.addView(amPmView, 0);
             // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
@@ -219,6 +219,11 @@
         }
     }
 
+    @Override
+    public boolean validateInput() {
+        return true;
+    }
+
     private void getHourFormatData() {
         final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mLocale,
                 (mIs24HourView) ? "Hm" : "hm");
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index bf0601d..789e60b 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -299,7 +299,7 @@
         if (mNextView == null) {
             throw new RuntimeException("This Toast was not created with Toast.makeText()");
         }
-        TextView tv = mNextView.findViewById(com.android.internal.R.id.message);
+        TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
         if (tv == null) {
             throw new RuntimeException("This Toast was not created with Toast.makeText()");
         }
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 1a3ca86..69b79971 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -264,7 +264,7 @@
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         inflater.inflate(com.android.internal.R.layout.zoom_container, container);
 
-        mControls = container.findViewById(com.android.internal.R.id.zoomControls);
+        mControls = (ZoomControls) container.findViewById(com.android.internal.R.id.zoomControls);
         mControls.setOnZoomInClickListener(new OnClickListener() {
             public void onClick(View v) {
                 dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ab1d9b9..4014217 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -36,7 +36,6 @@
 import com.android.internal.content.PackageMonitor;
 
 import android.app.ActivityManager;
-import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -115,6 +114,7 @@
 
     private static final String TAG = "ResolverActivity";
     private static final boolean DEBUG = false;
+    private Runnable mPostListBuildRunnable;
 
     private boolean mRegistered;
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -419,7 +419,9 @@
 
     protected CharSequence getTitleForAction(String action, int defaultTitleRes) {
         final ActionTitle title = mResolvingHome ? ActionTitle.HOME : ActionTitle.forAction(action);
-        final boolean named = mAdapter.hasFilteredItem();
+        // While there may already be a filtered item, we can only use it in the title if the list
+        // is already sorted and all information relevant to it is already in the list.
+        final boolean named = mAdapter.getFilteredPosition() > 0;
         if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
             return getString(defaultTitleRes);
         } else {
@@ -510,6 +512,9 @@
         if (!isChangingConfigurations() && mPickOptionRequest != null) {
             mPickOptionRequest.cancel();
         }
+        if (mPostListBuildRunnable != null) {
+            getMainThreadHandler().removeCallbacks(mPostListBuildRunnable);
+        }
     }
 
     @Override
@@ -590,6 +595,9 @@
         }
 
         TargetInfo target = mAdapter.targetInfoForPosition(which, filtered);
+        if (target == null) {
+            return;
+        }
         if (onTargetSelected(target, always)) {
             if (always && filtered) {
                 MetricsLogger.action(
@@ -880,15 +888,15 @@
         }
 
         setContentView(mLayoutId);
-        if (count > 0 || !rebuildCompleted) {
-            mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
-            onPrepareAdapterView(mAdapterView, mAdapter, mAlwaysUseOption);
-        } else {
+        mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
+
+        if (count == 0 && mAdapter.mPlaceholderCount == 0) {
             final TextView empty = (TextView) findViewById(R.id.empty);
             empty.setVisibility(View.VISIBLE);
-
-            mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
             mAdapterView.setVisibility(View.GONE);
+        } else {
+            mAdapterView.setVisibility(View.VISIBLE);
+            onPrepareAdapterView(mAdapterView, mAdapter, mAlwaysUseOption);
         }
         return false;
     }
@@ -917,16 +925,23 @@
     }
 
     public void setTitleAndIcon() {
-        if (mTitle == null) {
-            mTitle = getTitleForAction(getTargetIntent().getAction(), mDefaultTitleResId);
-        }
-
-        if (!TextUtils.isEmpty(mTitle)) {
+        if (mAdapter.getCount() == 0 && mAdapter.mPlaceholderCount == 0) {
             final TextView titleView = (TextView) findViewById(R.id.title);
             if (titleView != null) {
-                titleView.setText(mTitle);
+                titleView.setVisibility(View.GONE);
             }
-            setTitle(mTitle);
+        }
+
+        CharSequence title = mTitle != null
+                ? mTitle
+                : getTitleForAction(getTargetIntent().getAction(), mDefaultTitleResId);
+
+        if (!TextUtils.isEmpty(title)) {
+            final TextView titleView = (TextView) findViewById(R.id.title);
+            if (titleView != null) {
+                titleView.setText(title);
+            }
+            setTitle(title);
 
             // Try to initialize the title icon if we have a view for it and a title to match
             final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon);
@@ -963,9 +978,17 @@
             }
         }
 
-        if (mAdapter.hasFilteredItem()) {
+        if (mAdapter.getFilteredPosition() >= 0) {
             setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
             mOnceButton.setEnabled(true);
+            return;
+        }
+
+        // When the items load in, if an item was already selected, enable the buttons
+        if (mAdapterView != null
+                && mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
+            setAlwaysButtonEnabled(true, mAdapterView.getCheckedItemPosition(), true);
+            mOnceButton.setEnabled(true);
         }
     }
 
@@ -1234,6 +1257,7 @@
         private DisplayResolveInfo mOtherProfile;
         private boolean mHasExtendedInfo;
         private ResolverListController mResolverListController;
+        private int mPlaceholderCount;
 
         protected final LayoutInflater mInflater;
 
@@ -1265,6 +1289,10 @@
             }
         }
 
+        public void setPlaceholderCount(int count) {
+            mPlaceholderCount = count;
+        }
+
         public DisplayResolveInfo getFilteredItem() {
             if (mFilterLastUsed && mLastChosenPosition >= 0) {
                 // Not using getItem since it offsets to dodge this position for the list
@@ -1350,6 +1378,7 @@
                 }
 
                 if (N > 1) {
+                    setPlaceholderCount(currentResolveList.size());
                     AsyncTask<List<ResolvedComponentInfo>,
                             Void,
                             List<ResolvedComponentInfo>> sortingTask =
@@ -1366,13 +1395,26 @@
                         @Override
                         protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
                             processSortedList(sortedComponents);
-                            onPrepareAdapterView(mAdapterView, mAdapter, mAlwaysUseOption);
                             if (mProfileView != null) {
                                 bindProfileView();
                             }
+                            notifyDataSetChanged();
                         }
                     };
                     sortingTask.execute(currentResolveList);
+                    if (mPostListBuildRunnable == null) {
+                        mPostListBuildRunnable = new Runnable() {
+                            @Override
+                            public void run() {
+                                setTitleAndIcon();
+                                resetAlwaysOrOnceButtonBar();
+                                onListRebuilt();
+                                disableLastChosenIfNeeded();
+                                mPostListBuildRunnable = null;
+                            }
+                        };
+                        getMainThreadHandler().post(mPostListBuildRunnable);
+                    }
                     return false;
                 } else {
                     processSortedList(currentResolveList);
@@ -1563,21 +1605,33 @@
             }
         }
 
+        @Nullable
         public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
-            return (filtered ? getItem(position) : mDisplayList.get(position))
-                    .getResolveInfo();
+            TargetInfo target = targetInfoForPosition(position, filtered);
+            if (target != null) {
+                return target.getResolveInfo();
+             }
+             return null;
         }
 
+        @Nullable
         public TargetInfo targetInfoForPosition(int position, boolean filtered) {
-            return filtered ? getItem(position) : mDisplayList.get(position);
+            if (filtered) {
+                return getItem(position);
+            }
+            if (mDisplayList.size() > position) {
+                return mDisplayList.get(position);
+            }
+            return null;
         }
 
         public int getCount() {
-            int result = mDisplayList.size();
+            int totalSize = mDisplayList == null || mDisplayList.isEmpty() ? mPlaceholderCount :
+                    mDisplayList.size();
             if (mFilterLastUsed && mLastChosenPosition >= 0) {
-                result--;
+                totalSize--;
             }
-            return result;
+            return totalSize;
         }
 
         public int getUnfilteredCount() {
@@ -1592,11 +1646,16 @@
             return mDisplayList.get(index);
         }
 
+        @Nullable
         public TargetInfo getItem(int position) {
             if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
                 position++;
             }
-            return mDisplayList.get(position);
+            if (mDisplayList.size() > position) {
+                return mDisplayList.get(position);
+            } else {
+                return null;
+            }
         }
 
         public long getItemId(int position) {
@@ -1660,6 +1719,11 @@
 
         private void onBindView(View view, TargetInfo info) {
             final ViewHolder holder = (ViewHolder) view.getTag();
+            if (info == null) {
+                holder.icon.setImageDrawable(
+                        getDrawable(R.drawable.resolver_icon_placeholder));
+                return;
+            }
             final CharSequence label = info.getDisplayLabel();
             if (!TextUtils.equals(holder.text.getText(), label)) {
                 holder.text.setText(info.getDisplayLabel());
@@ -1770,6 +1834,11 @@
                 // Header views don't count.
                 return;
             }
+            // If we're still loading, we can't yet enable the buttons.
+            if (mAdapter.resolveInfoForPosition(position, true) == null) {
+                return;
+            }
+
             final int checkedPos = mAdapterView.getCheckedItemPosition();
             final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
             if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
diff --git a/core/java/com/android/internal/app/procstats/PssTable.java b/core/java/com/android/internal/app/procstats/PssTable.java
index b6df983..de5f673 100644
--- a/core/java/com/android/internal/app/procstats/PssTable.java
+++ b/core/java/com/android/internal/app/procstats/PssTable.java
@@ -96,7 +96,7 @@
             }
 
             val = getValue(key, PSS_USS_AVERAGE);
-            setValue(key, PSS_AVERAGE,
+            setValue(key, PSS_USS_AVERAGE,
                     (long)(((val*(double)count)+(avgUss*(double)inCount)) / (count+inCount)));
 
             val = getValue(key, PSS_USS_MAXIMUM);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index a94b161..dfc0696 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -42,8 +42,9 @@
 /**
  * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
  * <p>
- * This class is designed to be used from and only from {@link InputMethodManagerService} by using
- * {@link InputMethodManagerService#mMethodMap} as a global lock.
+ * This class is designed to be used from and only from
+ * {@link com.android.server.InputMethodManagerService} by using
+ * {@link com.android.server.InputMethodManagerService#mMethodMap} as a global lock.
  * </p>
  */
 public class InputMethodSubtypeSwitchingController {
@@ -106,21 +107,39 @@
             return c1.toString().compareTo(c2.toString());
         }
 
+        /**
+         * Compares this object with the specified object for order. The fields of this class will
+         * be compared in the following order.
+         * <ol>
+         *   <li>{@link #mImeName}</li>
+         *   <li>{@link #mIsSystemLocale}</li>
+         *   <li>{@link #mIsSystemLanguage}</li>
+         *   <li>{@link #mSubtypeName}</li>
+         * </ol>
+         * Note: this class has a natural ordering that is inconsistent with {@link #equals(Object).
+         * This method doesn't compare {@link #mSubtypeId} but {@link #equals(Object)} does.
+         *
+         * @param other the object to be compared.
+         * @return a negative integer, zero, or positive integer as this object is less than, equal
+         *         to, or greater than the specified <code>other</code> object.
+         */
         @Override
         public int compareTo(ImeSubtypeListItem other) {
             int result = compareNullableCharSequences(mImeName, other.mImeName);
             if (result != 0) {
                 return result;
             }
-            result = compareNullableCharSequences(mSubtypeName, other.mSubtypeName);
-            if (result != 0) {
-                return result;
-            }
+            // Subtype that has the same locale of the system's has higher priority.
             result = (mIsSystemLocale ? -1 : 0) - (other.mIsSystemLocale ? -1 : 0);
             if (result != 0) {
                 return result;
             }
-            return (mIsSystemLanguage ? -1 : 0) - (other.mIsSystemLanguage ? -1 : 0);
+            // Subtype that has the same language of the system's has higher priority.
+            result = (mIsSystemLanguage ? -1 : 0) - (other.mIsSystemLanguage ? -1 : 0);
+            if (result != 0) {
+                return result;
+            }
+            return compareNullableCharSequences(mSubtypeName, other.mSubtypeName);
         }
 
         @Override
@@ -141,13 +160,7 @@
             }
             if (o instanceof ImeSubtypeListItem) {
                 final ImeSubtypeListItem that = (ImeSubtypeListItem)o;
-                if (!Objects.equals(this.mImi, that.mImi)) {
-                    return false;
-                }
-                if (this.mSubtypeId != that.mSubtypeId) {
-                    return false;
-                }
-                return true;
+                return Objects.equals(this.mImi, that.mImi) && this.mSubtypeId == that.mSubtypeId;
             }
             return false;
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 63622f1..9dca5ea 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -9562,7 +9562,8 @@
                     }
                 });
 
-        if (DEBUG_ENERGY_CPU) {
+        // TODO: STOPSHIP, remove the "true" below after b/34961340 is fixed
+        if (DEBUG_ENERGY_CPU || true) {
             Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
                     " ms");
         }
@@ -10390,10 +10391,9 @@
             if (next == null) {
                 return;
             }
-
-            mWriteLock.lock();
         }
 
+        mWriteLock.lock();
         try {
             FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
             stream.write(next.marshall());
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 304c31d..f4be128 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -43,8 +43,8 @@
  * @hide
  */
 public class RuntimeInit {
-    private final static String TAG = "AndroidRuntime";
-    private final static boolean DEBUG = false;
+    final static String TAG = "AndroidRuntime";
+    final static boolean DEBUG = false;
 
     /** true if commonInit() has been called */
     private static boolean initialized;
@@ -53,7 +53,6 @@
 
     private static volatile boolean mCrashing = false;
 
-    private static final native void nativeZygoteInit();
     private static final native void nativeFinishInit();
     private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
 
@@ -133,7 +132,7 @@
         }
     }
 
-    private static final void commonInit() {
+    protected static final void commonInit() {
         if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
 
         /*
@@ -287,50 +286,7 @@
         if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
     }
 
-    /**
-     * The main function called when started through the zygote process. This
-     * could be unified with main(), if the native code in nativeFinishInit()
-     * were rationalized with Zygote startup.<p>
-     *
-     * Current recognized args:
-     * <ul>
-     *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
-     * </ul>
-     *
-     * @param targetSdkVersion target SDK version
-     * @param argv arg strings
-     */
-    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
-            throws Zygote.MethodAndArgsCaller {
-        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
-
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
-        redirectLogStreams();
-
-        commonInit();
-        nativeZygoteInit();
-        applicationInit(targetSdkVersion, argv, classLoader);
-    }
-
-    /**
-     * The main function called when an application is started through a
-     * wrapper process.
-     *
-     * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
-     * which calls {@link WrapperInit#main} which then calls this method.
-     * So we don't need to call commonInit() here.
-     *
-     * @param targetSdkVersion target SDK version
-     * @param argv arg strings
-     */
-    public static void wrapperInit(int targetSdkVersion, String[] argv)
-            throws Zygote.MethodAndArgsCaller {
-        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
-
-        applicationInit(targetSdkVersion, argv, null);
-    }
-
-    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
+    protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
             throws Zygote.MethodAndArgsCaller {
         // If the application calls System.exit(), terminate the process
         // immediately without running any shutdown hooks.  It is not possible to
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index c03bcdf..96468ab 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -20,7 +20,7 @@
 import android.os.Trace;
 import android.util.BootTimingsTraceLog;
 import android.util.Slog;
-
+import com.android.internal.os.Zygote.MethodAndArgsCaller;
 import dalvik.system.VMRuntime;
 import java.io.DataOutputStream;
 import java.io.FileDescriptor;
@@ -83,7 +83,7 @@
             // Launch the application.
             String[] runtimeArgs = new String[args.length - 2];
             System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
-            RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
+            WrapperInit.wrapperInit(targetSdkVersion, runtimeArgs);
         } catch (Zygote.MethodAndArgsCaller caller) {
             caller.run();
         }
@@ -124,4 +124,24 @@
         Zygote.appendQuotedShellArgs(command, args);
         Zygote.execShell(command.toString());
     }
+
+    /**
+     * The main function called when an application is started through a
+     * wrapper process.
+     *
+     * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
+     * which calls {@link main} which then calls this method.
+     * So we don't need to call commonInit() here.
+     *
+     * @param targetSdkVersion target SDK version
+     * @param argv arg strings
+     */
+    private static void wrapperInit(int targetSdkVersion, String[] argv)
+            throws Zygote.MethodAndArgsCaller {
+        if (RuntimeInit.DEBUG) {
+            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper");
+        }
+
+        RuntimeInit.applicationInit(targetSdkVersion, argv, null);
+    }
 }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 8fe374c..a7f311b 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -789,7 +789,7 @@
                     VMRuntime.getCurrentInstructionSet(),
                     pipeFd, parsedArgs.remainingArgs);
         } else {
-            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
+            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
                     parsedArgs.remainingArgs, null /* classLoader */);
         }
     }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 6e3b383..8d31990 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -45,6 +45,7 @@
 import android.util.BootTimingsTraceLog;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Slog;
 import android.webkit.WebViewFactory;
 import android.widget.TextView;
 
@@ -484,7 +485,7 @@
             /*
              * Pass the remaining arguments to SystemServer.
              */
-            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
+            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
         }
 
         /* should never reach here */
@@ -784,4 +785,33 @@
      */
     private ZygoteInit() {
     }
+
+    /**
+     * The main function called when started through the zygote process. This
+     * could be unified with main(), if the native code in nativeFinishInit()
+     * were rationalized with Zygote startup.<p>
+     *
+     * Current recognized args:
+     * <ul>
+     *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
+     * </ul>
+     *
+     * @param targetSdkVersion target SDK version
+     * @param argv arg strings
+     */
+    public static final void zygoteInit(int targetSdkVersion, String[] argv,
+            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
+        if (RuntimeInit.DEBUG) {
+            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
+        RuntimeInit.redirectLogStreams();
+
+        RuntimeInit.commonInit();
+        ZygoteInit.nativeZygoteInit();
+        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
+    }
+
+    private static final native void nativeZygoteInit();
 }
diff --git a/core/java/com/android/internal/policy/PipMotionHelper.java b/core/java/com/android/internal/policy/PipMotionHelper.java
deleted file mode 100644
index 944cd32..0000000
--- a/core/java/com/android/internal/policy/PipMotionHelper.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import android.animation.RectEvaluator;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * A helper to animate the PIP.
- */
-public class PipMotionHelper {
-
-    private static final String TAG = "PipMotionHelper";
-
-    private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
-    private static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
-    private static final int DEFAULT_DURATION = 225;
-
-    private IActivityManager mActivityManager;
-    private Handler mHandler;
-
-    public PipMotionHelper(Handler handler) {
-        mHandler = handler;
-    }
-
-    /**
-     * Moves the PIP to give given {@param bounds}.
-     */
-    public void resizeToBounds(Rect toBounds) {
-        mHandler.post(() -> {
-            if (mActivityManager == null) {
-                mActivityManager = ActivityManager.getService();
-            }
-            try {
-                mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Could not move pinned stack to bounds: " + toBounds, e);
-            }
-        });
-    }
-
-    /**
-     * Creates an animation to move the PIP to give given {@param toBounds} with the default
-     * animation properties.
-     */
-    public ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds) {
-        return createAnimationToBounds(fromBounds, toBounds, DEFAULT_DURATION, FAST_OUT_SLOW_IN,
-                null);
-    }
-
-    /**
-     * Creates an animation to move the PIP to give given {@param toBounds}.
-     */
-    public ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds, int duration,
-            Interpolator interpolator, ValueAnimator.AnimatorUpdateListener updateListener) {
-        ValueAnimator anim = ValueAnimator.ofObject(RECT_EVALUATOR, fromBounds, toBounds);
-        anim.setDuration(duration);
-        anim.setInterpolator(interpolator);
-        anim.addUpdateListener((ValueAnimator animation) -> {
-            resizeToBounds((Rect) animation.getAnimatedValue());
-        });
-        if (updateListener != null) {
-            anim.addUpdateListener(updateListener);
-        }
-        return anim;
-    }
-
-
-}
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index ec92aa9..bf047c1 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -84,13 +84,6 @@
     }
 
     /**
-     * Enables snapping to the closest edge.
-     */
-    public void setSnapToEdge(boolean snapToEdge) {
-        mSnapMode = snapToEdge ? SNAP_MODE_EDGE : mDefaultSnapMode;
-    }
-
-    /**
      * @return the closest absolute snap stack bounds for the given {@param stackBounds} moving at
      * the given {@param velocityX} and {@param velocityY}.  The {@param movementBounds} should be
      * those for the given {@param stackBounds}.
@@ -233,6 +226,21 @@
     }
 
     /**
+     * Adjusts {@param movementBoundsOut} so that it is the movement bounds for the given
+     * {@param stackBounds}.
+     */
+    public void getMovementBounds(Rect stackBounds, Rect insetBounds, Rect movementBoundsOut,
+            int imeHeight) {
+        // Adjust the right/bottom to ensure the stack bounds never goes offscreen
+        movementBoundsOut.set(insetBounds);
+        movementBoundsOut.right = Math.max(insetBounds.left, insetBounds.right -
+                stackBounds.width());
+        movementBoundsOut.bottom = Math.max(insetBounds.top, insetBounds.bottom -
+                stackBounds.height());
+        movementBoundsOut.bottom -= imeHeight;
+    }
+
+    /**
      * @return the closest point in {@param points} to the given {@param x} and {@param y}.
      */
     private Point findClosestPoint(int x, int y, Point[] points) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 20f10b3..9cbbc5a 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -53,9 +53,6 @@
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
     void setWindowState(int window, int state);
-    void buzzBeepBlinked();
-    void notificationLightOff();
-    void notificationLightPulse(int argb, int millisOn, int millisOff);
 
     void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
     void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
index 67d7b3e..6a25964 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
@@ -16,16 +16,32 @@
 
 package com.android.internal.textservice;
 
+import com.android.internal.textservice.ISpellCheckerServiceCallback;
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 
 import android.os.Bundle;
 
 /**
- * Public interface to the global spell checker.
+ * IPC channels from TextServicesManagerService to SpellCheckerService.
  * @hide
  */
-interface ISpellCheckerService {
-    ISpellCheckerSession getISpellCheckerSession(
-            String locale, ISpellCheckerSessionListener listener, in Bundle bundle);
+oneway interface ISpellCheckerService {
+    /**
+     * Called from the system when an application is requesting a new spell checker session.
+     *
+     * <p>Note: This is an internal protocol used by the system to establish spell checker sessions,
+     * which is not guaranteed to be stable and is subject to change.</p>
+     *
+     * @param locale locale to be returned from
+     *               {@link android.service.textservice.SpellCheckerService.Session#getLocale()}
+     * @param listener IPC channel object to be used to implement
+     *                 {@link android.service.textservice.SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)} and
+     *                 {@link android.service.textservice.SpellCheckerService.Session#onGetSuggestions(TextInfo, int)}
+     * @param bundle bundle to be returned from {@link android.service.textservice.SpellCheckerService.Session#getBundle()}
+     * @param callback IPC channel to return the result to the caller in an asynchronous manner
+     */
+    void getISpellCheckerSession(
+            String locale, ISpellCheckerSessionListener listener, in Bundle bundle,
+            ISpellCheckerServiceCallback callback);
 }
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerServiceCallback.aidl b/core/java/com/android/internal/textservice/ISpellCheckerServiceCallback.aidl
new file mode 100644
index 0000000..e716cc1
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerServiceCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
+import android.os.Bundle;
+
+/**
+ * IPC channels from SpellCheckerService to TextServicesManagerService.
+ * @hide
+ */
+oneway interface ISpellCheckerServiceCallback {
+    // TODO: Currently SpellCheckerSession just ignores null newSession and continues waiting for
+    // the next onSessionCreated with non-null newSession, which is supposed to never happen if
+    // the system is working normally. We should at least free up resources in SpellCheckerSession.
+    // Note: This method is called from non-system processes, in theory we cannot assume that
+    // this method is always be called only once with non-null value.
+    void onSessionCreated(ISpellCheckerSession newSession);
+}
diff --git a/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
index ecb6cd0..08d2a5d 100644
--- a/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
+++ b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
@@ -21,7 +21,7 @@
 import android.view.textservice.SpellCheckerInfo;
 
 /**
- * Interface to the text service session.
+ * (Per-session) IPC channels from TextServicesManagerService to spell checker client applications.
  * @hide
  */
 interface ITextServicesSessionListener {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index a9a6364..cb3a250 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -435,10 +435,6 @@
         }
     }
 
-    public static <T> boolean contains(@Nullable ArraySet<T> cur, T val) {
-        return (cur != null) ? cur.contains(val) : false;
-    }
-
     public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
         if (cur == null) {
             cur = new ArrayList<>();
@@ -459,6 +455,16 @@
         }
     }
 
+    /**
+     * Returns the given list, or an immutable empty list if the provided list is null
+     *
+     * @see Collections#emptyList
+     */
+
+    public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) {
+        return cur == null ? Collections.emptyList() : cur;
+    }
+
     public static <T> boolean contains(@Nullable Collection<T> cur, T val) {
         return (cur != null) ? cur.contains(val) : false;
     }
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
index 184245e..e733c30 100644
--- a/core/java/com/android/internal/util/MessageUtils.java
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -42,10 +42,11 @@
 
     /**
      * Finds the names of integer constants. Searches the specified {@code classes}, looking for
-     * accessible static integer fields whose names begin with one of the specified {@prefixes}.
+     * accessible static integer fields whose names begin with one of the specified
+     * {@code prefixes}.
      *
      * @param classes the classes to examine.
-     * @prefixes only consider fields names starting with one of these prefixes.
+     * @param prefixes only consider fields names starting with one of these prefixes.
      * @return a {@link SparseArray} mapping integer constants to their names.
      */
     public static SparseArray<String> findMessageNames(Class[] classes, String[] prefixes) {
@@ -122,7 +123,6 @@
      * accessible static integer values whose names begin with {@link #DEFAULT_PREFIXES}.
      *
      * @param classNames the classes to examine.
-     * @prefixes only consider fields names starting with one of these prefixes.
      * @return a {@link SparseArray} mapping integer constants to their names.
      */
     public static SparseArray<String> findMessageNames(Class[] classNames) {
diff --git a/core/java/android/service/autofill/CallbackHelper.java b/core/java/com/android/internal/util/ObjectUtils.java
similarity index 65%
copy from core/java/android/service/autofill/CallbackHelper.java
copy to core/java/com/android/internal/util/ObjectUtils.java
index ded8f97..d109a5a 100644
--- a/core/java/android/service/autofill/CallbackHelper.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -13,18 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.autofill;
 
-import java.io.PrintWriter;
 
-final class CallbackHelper {
+package com.android.internal.util;
 
-    static interface Dumpable {
-        void dump(String prefix, PrintWriter pw);
-        void setFinalizer(Finalizer f);
-    }
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 
-    static interface Finalizer {
-        void gone();
+/** @hide */
+public class ObjectUtils {
+    private ObjectUtils() {}
+
+    @NonNull
+    public static <T> T firstNotNull(@Nullable T a, @NonNull T b) {
+        return a != null ? a : Preconditions.checkNotNull(b);
     }
 }
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 0185e30..cb2d885 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -57,7 +57,6 @@
     private static final int DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 81;
     private static final int DO_BEGIN_BATCH_EDIT = 90;
     private static final int DO_END_BATCH_EDIT = 95;
-    private static final int DO_REPORT_FULLSCREEN_MODE = 100;
     private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
     private static final int DO_CLEAR_META_KEY_STATES = 130;
     private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
@@ -73,8 +72,6 @@
     private Object mLock = new Object();
     @GuardedBy("mLock")
     private boolean mFinished = false;
-    @GuardedBy("mLock")
-    private String mInputMethodId;
 
     static class SomeArgs {
         Object arg1;
@@ -113,18 +110,6 @@
         }
     }
 
-    public String getInputMethodId() {
-        synchronized (mLock) {
-            return mInputMethodId;
-        }
-    }
-
-    public void setInputMethodId(final String inputMethodId) {
-        synchronized (mLock) {
-            mInputMethodId = inputMethodId;
-        }
-    }
-
     abstract protected boolean isActive();
 
     /**
@@ -133,14 +118,6 @@
      */
     abstract protected void onUserAction();
 
-    /**
-     * Called when the input method started or stopped full-screen mode.
-     * @param enabled {@code true} if the input method starts full-screen mode.
-     * @param calledInBackground {@code true} if this input connection is in a state when incoming
-     * events are usually ignored.
-     */
-    abstract protected void onReportFullscreenMode(boolean enabled, boolean calledInBackground);
-
     public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
         dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
     }
@@ -225,10 +202,6 @@
         dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
     }
 
-    public void reportFullscreenMode(boolean enabled) {
-        dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
-    }
-
     public void performPrivateCommand(String action, Bundle data) {
         dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
     }
@@ -486,23 +459,6 @@
                 ic.endBatchEdit();
                 return;
             }
-            case DO_REPORT_FULLSCREEN_MODE: {
-                InputConnection ic = getInputConnection();
-                boolean isBackground = false;
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "reportFullscreenMode on inexistent InputConnection");
-                    isBackground = true;
-                }
-                final boolean enabled = msg.arg1 == 1;
-                if (!isBackground) {
-                    ic.reportFullscreenMode(enabled);
-                }
-                // Due to the nature of asynchronous event handling, currently InputMethodService
-                // has relied on the fact that #reportFullscreenMode() can be handled even when the
-                // InputConnection is inactive.  We have to notify this event to InputMethodManager.
-                onReportFullscreenMode(enabled, isBackground);
-                return;
-            }
             case DO_PERFORM_PRIVATE_COMMAND: {
                 InputConnection ic = getInputConnection();
                 if (ic == null || !isActive()) {
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 728c557..c227991 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -62,9 +62,7 @@
     void beginBatchEdit();
     
     void endBatchEdit();
-    
-    void reportFullscreenMode(boolean enabled);
-    
+
     void sendKeyEvent(in KeyEvent event);
     
     void clearMetaKeyStates(int states);
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 81056f2..ffa9f75 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -27,6 +27,7 @@
     void onBindMethod(in InputBindResult res);
     // unbindReason corresponds to InputMethodClient.UnbindReason.
     void onUnbindMethod(int sequence, int unbindReason);
-    void setActive(boolean active);
+    void setActive(boolean active, boolean fullscreen);
     void setUserActionNotificationSequenceNumber(int sequenceNumber);
+    void reportFullscreenMode(boolean fullscreen);
 }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 9e4b43b..2279a67 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -86,5 +86,7 @@
     IInputContentUriToken createInputContentUriToken(in IBinder token, in Uri contentUri,
             in String packageName);
 
+    void reportFullscreenMode(in IBinder token, boolean fullscreen);
+
     oneway void notifyUserAction(int sequenceNumber);
 }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 9a09dcc..cc0ef75 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -467,12 +467,8 @@
     }
 
     public boolean reportFullscreenMode(boolean enabled) {
-        try {
-            mIInputContext.reportFullscreenMode(enabled);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
+        // Nothing should happen when called from input method.
+        return false;
     }
 
     public boolean performPrivateCommand(String action, Bundle data) {
diff --git a/core/java/com/android/internal/view/InputMethodClient.java b/core/java/com/android/internal/view/InputMethodClient.java
index c27e9aa..802ce3e 100644
--- a/core/java/com/android/internal/view/InputMethodClient.java
+++ b/core/java/com/android/internal/view/InputMethodClient.java
@@ -32,13 +32,14 @@
     public static final int START_INPUT_REASON_UNBOUND_FROM_IMMS = 6;
     public static final int START_INPUT_REASON_ACTIVATED_BY_IMMS = 7;
     public static final int START_INPUT_REASON_DEACTIVATED_BY_IMMS = 8;
+    public static final int START_INPUT_REASON_SESSION_CREATED_BY_IME = 9;
 
     @Retention(SOURCE)
     @IntDef({START_INPUT_REASON_UNSPECIFIED, START_INPUT_REASON_WINDOW_FOCUS_GAIN,
             START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY,
             START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API, START_INPUT_REASON_CHECK_FOCUS,
             START_INPUT_REASON_BOUND_TO_IMMS, START_INPUT_REASON_ACTIVATED_BY_IMMS,
-            START_INPUT_REASON_DEACTIVATED_BY_IMMS})
+            START_INPUT_REASON_DEACTIVATED_BY_IMMS, START_INPUT_REASON_SESSION_CREATED_BY_IME})
     public @interface StartInputReason {}
 
     public static String getStartInputReason(@StartInputReason final int reason) {
@@ -61,6 +62,8 @@
                 return "ACTIVATED_BY_IMMS";
             case START_INPUT_REASON_DEACTIVATED_BY_IMMS:
                 return "DEACTIVATED_BY_IMMS";
+            case START_INPUT_REASON_SESSION_CREATED_BY_IME:
+                return "SESSION_CREATED_BY_IME";
             default:
                 return "Unknown=" + reason;
         }
diff --git a/core/java/com/android/internal/view/menu/ActionMenu.java b/core/java/com/android/internal/view/menu/ActionMenu.java
index 3d44ebc..c657b87 100644
--- a/core/java/com/android/internal/view/menu/ActionMenu.java
+++ b/core/java/com/android/internal/view/menu/ActionMenu.java
@@ -38,7 +38,7 @@
     private boolean mIsQwerty;
     
     private ArrayList<ActionMenuItem> mItems;
-    
+
     public ActionMenu(Context context) {
         mContext = context;
         mItems = new ArrayList<ActionMenuItem>();
@@ -157,18 +157,22 @@
         
         return false;
     }
-    
+
     private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) {
         // TODO Make this smarter.
         final boolean qwerty = mIsQwerty;
         final ArrayList<ActionMenuItem> items = mItems;
         final int itemCount = items.size();
-        
+        final int modifierState = event.getModifiers();
         for (int i = 0; i < itemCount; i++) {
             ActionMenuItem item = items.get(i);
             final char shortcut = qwerty ? item.getAlphabeticShortcut() :
                     item.getNumericShortcut();
-            if (keyCode == shortcut) {
+            final int shortcutModifiers =
+                    qwerty ? item.getAlphabeticModifiers() : item.getNumericModifiers();
+            final boolean is_modifiers_exact_match = (modifierState & SUPPORTED_MODIFIERS_MASK)
+                    == (shortcutModifiers & SUPPORTED_MODIFIERS_MASK);
+            if ((keyCode == shortcut) && is_modifiers_exact_match) {
                 return item;
             }
         }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index 1fce0b7..ace0cce 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -21,6 +21,7 @@
 import android.graphics.drawable.Drawable;
 import android.view.ActionProvider;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
@@ -33,12 +34,14 @@
     private final int mGroup;
     private final int mCategoryOrder;
     private final int mOrdering;
-    
+
     private CharSequence mTitle;
     private CharSequence mTitleCondensed;
     private Intent mIntent;
     private char mShortcutNumericChar;
+    private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON;
     private char mShortcutAlphabeticChar;
+    private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON;
 
     private Drawable mIconDrawable;
     private int mIconResId = NO_ICON;
@@ -73,6 +76,10 @@
         return mShortcutAlphabeticChar;
     }
 
+    public int getAlphabeticModifiers() {
+        return mShortcutAlphabeticModifiers;
+    }
+
     public int getGroupId() {
         return mGroup;
     }
@@ -97,6 +104,10 @@
         return mShortcutNumericChar;
     }
 
+    public int getNumericModifiers() {
+        return mShortcutNumericModifiers;
+    }
+
     public int getOrder() {
         return mOrdering;
     }
@@ -138,6 +149,12 @@
         return this;
     }
 
+    public MenuItem setAlphabeticShortcut(char alphachar, int alphaModifiers) {
+        mShortcutAlphabeticChar = alphachar;
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+        return this;
+    }
+
     public MenuItem setCheckable(boolean checkable) {
         mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
         return this;
@@ -180,6 +197,12 @@
         return this;
     }
 
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        return this;
+    }
+
     public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
         mClickListener = menuItemClickListener;
         return this;
@@ -191,6 +214,15 @@
         return this;
     }
 
+    public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
+            int alphaModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        mShortcutAlphabeticChar = alphaChar;
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+        return this;
+    }
+
     public MenuItem setTitle(CharSequence title) {
         mTitle = title;
         return this;
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index df57639..7eb0f4d 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -805,7 +805,7 @@
      */
     void findItemsWithShortcutForKey(List<MenuItemImpl> items, int keyCode, KeyEvent event) {
         final boolean qwerty = isQwertyMode();
-        final int metaState = event.getMetaState();
+        final int modifierState = event.getModifiers();
         final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
         // Get the chars associated with the keyCode (i.e using any chording combo)
         final boolean isKeyCodeMapped = event.getKeyData(possibleChars);
@@ -821,9 +821,13 @@
             if (item.hasSubMenu()) {
                 ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event);
             }
-            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
-            if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) &&
-                  (shortcutChar != 0) &&
+            final char shortcutChar =
+                    qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
+            final int shortcutModifiers =
+                    qwerty ? item.getAlphabeticModifiers() : item.getNumericModifiers();
+            final boolean isModifiersExactMatch = (modifierState & SUPPORTED_MODIFIERS_MASK)
+                    == (shortcutModifiers & SUPPORTED_MODIFIERS_MASK);
+            if (isModifiersExactMatch && (shortcutChar != 0) &&
                   (shortcutChar == possibleChars.meta[0]
                       || shortcutChar == possibleChars.meta[2]
                       || (qwerty && shortcutChar == '\b' &&
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 342943f..4c3118d 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -25,6 +25,7 @@
 import android.util.Log;
 import android.view.ActionProvider;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
@@ -50,7 +51,9 @@
     private CharSequence mTitleCondensed;
     private Intent mIntent;
     private char mShortcutNumericChar;
+    private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON;
     private char mShortcutAlphabeticChar;
+    private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON;
 
     /** The icon's drawable which is only created as needed */
     private Drawable mIconDrawable;
@@ -227,18 +230,36 @@
         mItemCallback = callback;
         return this;
     }
-    
+
     public char getAlphabeticShortcut() {
         return mShortcutAlphabeticChar;
     }
 
+    public int getAlphabeticModifiers() {
+        return mShortcutAlphabeticModifiers;
+    }
+
     public MenuItem setAlphabeticShortcut(char alphaChar) {
         if (mShortcutAlphabeticChar == alphaChar) return this;
-        
+
         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
-        
+
         mMenu.onItemsChanged(false);
-        
+
+        return this;
+    }
+
+    public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers){
+        if (mShortcutAlphabeticChar == alphaChar &&
+                mShortcutAlphabeticModifiers == alphaModifiers) {
+            return this;
+        }
+
+        mShortcutAlphabeticChar = alphaChar;
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+
+        mMenu.onItemsChanged(false);
+
         return this;
     }
 
@@ -246,6 +267,10 @@
         return mShortcutNumericChar;
     }
 
+    public int getNumericModifiers() {
+        return mShortcutNumericModifiers;
+    }
+
     public MenuItem setNumericShortcut(char numericChar) {
         if (mShortcutNumericChar == numericChar) return this;
         
@@ -256,6 +281,19 @@
         return this;
     }
 
+    public MenuItem setNumericShortcut(char numericChar, int numericModifiers){
+        if (mShortcutNumericChar == numericChar && mShortcutNumericModifiers == numericModifiers) {
+            return this;
+        }
+
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
     public MenuItem setShortcut(char numericChar, char alphaChar) {
         mShortcutNumericChar = numericChar;
         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
@@ -265,6 +303,18 @@
         return this;
     }
 
+    public MenuItem setShortcut(char numericChar, int numericModifiers, char alphaChar,
+            int alphaModifiers) {
+        mShortcutNumericChar = numericChar;
+        mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
+        mShortcutAlphabeticChar = alphaChar;
+        mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
     /**
      * @return The active shortcut (based on QWERTY-mode of the menu).
      */
diff --git a/core/java/com/android/internal/widget/DrawingSpace.java b/core/java/com/android/internal/widget/DrawingSpace.java
deleted file mode 100644
index b8222db..0000000
--- a/core/java/com/android/internal/widget/DrawingSpace.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * Implementation of {@link android.widget.Space} that uses normal View drawing
- * rather than a no-op. Useful for dialogs and other places where the base View
- * class is too greedy when measured with AT_MOST.
- */
-public final class DrawingSpace extends View {
-    public DrawingSpace(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    public DrawingSpace(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public DrawingSpace(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public DrawingSpace(Context context) {
-        this(context, null);
-    }
-
-    /**
-     * Compare to: {@link View#getDefaultSize(int, int)}
-     * <p>
-     * If mode is AT_MOST, return the child size instead of the parent size
-     * (unless it is too big).
-     */
-    private static int getDefaultSizeNonGreedy(int size, int measureSpec) {
-        int result = size;
-        int specMode = MeasureSpec.getMode(measureSpec);
-        int specSize = MeasureSpec.getSize(measureSpec);
-
-        switch (specMode) {
-            case MeasureSpec.UNSPECIFIED:
-                result = size;
-                break;
-            case MeasureSpec.AT_MOST:
-                result = Math.min(size, specSize);
-                break;
-            case MeasureSpec.EXACTLY:
-                result = specSize;
-                break;
-        }
-        return result;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        setMeasuredDimension(
-                getDefaultSizeNonGreedy(getSuggestedMinimumWidth(), widthMeasureSpec),
-                getDefaultSizeNonGreedy(getSuggestedMinimumHeight(), heightMeasureSpec));
-    }
-}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 58e694a..854d013 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -32,6 +32,7 @@
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.Size;
+import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -1113,6 +1114,7 @@
             mMainPanel.removeAllViews();
             mMainPanel.setPaddingRelative(0, 0, 0, 0);
 
+            int lastGroupId = -1;
             boolean isFirstItem = true;
             while (!remainingMenuItems.isEmpty()) {
                 final MenuItem menuItem = remainingMenuItems.peek();
@@ -1125,11 +1127,11 @@
                             menuItemButton.getPaddingTop(),
                             menuItemButton.getPaddingEnd(),
                             menuItemButton.getPaddingBottom());
-                    isFirstItem = false;
                 }
 
                 // Adding additional end padding for the last button to even out button spacing.
-                if (remainingMenuItems.size() == 1) {
+                boolean isLastItem = remainingMenuItems.size() == 1;
+                if (isLastItem) {
                     menuItemButton.setPaddingRelative(
                             menuItemButton.getPaddingStart(),
                             menuItemButton.getPaddingTop(),
@@ -1138,25 +1140,64 @@
                 }
 
                 menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-                int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
+                final int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
+
+                final boolean isNewGroup = !isFirstItem && lastGroupId != menuItem.getGroupId();
+                final int extraPadding = isNewGroup ? menuItemButton.getPaddingEnd() * 2 : 0;
+
                 // Check if we can fit an item while reserving space for the overflowButton.
                 boolean canFitWithOverflow =
-                        menuItemButtonWidth <= availableWidth - mOverflowButtonSize.getWidth();
+                        menuItemButtonWidth <=
+                                availableWidth - mOverflowButtonSize.getWidth() - extraPadding;
                 boolean canFitNoOverflow =
-                        remainingMenuItems.size() == 1 && menuItemButtonWidth <= availableWidth;
+                        isLastItem && menuItemButtonWidth <= availableWidth - extraPadding;
                 if (canFitWithOverflow || canFitNoOverflow) {
+                    if (isNewGroup) {
+                        final View border = createBorder(mContext);
+                        final int borderWidth = border.getLayoutParams().width;
+
+                        // Add extra padding to the end of the previous button.
+                        // Half of the extra padding (less borderWidth) goes to the previous button.
+                        View previousButton = mMainPanel.getChildAt(mMainPanel.getChildCount() - 1);
+                        final int prevPaddingEnd = previousButton.getPaddingEnd()
+                                + extraPadding / 2 - borderWidth;
+                        previousButton.setPaddingRelative(
+                                previousButton.getPaddingStart(),
+                                previousButton.getPaddingTop(),
+                                prevPaddingEnd,
+                                previousButton.getPaddingBottom());
+                        final ViewGroup.LayoutParams prevParams = previousButton.getLayoutParams();
+                        prevParams.width += extraPadding / 2 - borderWidth;
+                        previousButton.setLayoutParams(prevParams);
+
+                        // Add extra padding to the start of this button.
+                        // Other half of the extra padding goes to this button.
+                        final int paddingStart = menuItemButton.getPaddingStart()
+                                + extraPadding / 2;
+                        menuItemButton.setPaddingRelative(
+                                paddingStart,
+                                menuItemButton.getPaddingTop(),
+                                menuItemButton.getPaddingEnd(),
+                                menuItemButton.getPaddingBottom());
+
+                        // Include a border.
+                        mMainPanel.addView(border);
+                    }
+
                     setButtonTagAndClickListener(menuItemButton, menuItem);
                     mMainPanel.addView(menuItemButton);
-                    ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
-                    params.width = menuItemButtonWidth;
+                    final ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
+                    params.width = menuItemButtonWidth + extraPadding / 2;
                     menuItemButton.setLayoutParams(params);
-                    availableWidth -= menuItemButtonWidth;
+                    availableWidth -= menuItemButtonWidth + extraPadding;
                     remainingMenuItems.pop();
                 } else {
                     // Reserve space for overflowButton.
                     mMainPanel.setPaddingRelative(0, 0, mOverflowButtonSize.getWidth(), 0);
                     break;
                 }
+                lastGroupId = menuItem.getGroupId();
+                isFirstItem = false;
             }
             mMainPanelSize = measure(mMainPanel);
             return remainingMenuItems;
@@ -1688,6 +1729,23 @@
         return popupWindow;
     }
 
+    private static View createBorder(Context context) {
+        // TODO: Inflate this instead.
+        View border = new View(context);
+        int _1dp = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, 1, context.getResources().getDisplayMetrics());
+        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                _1dp, ViewGroup.LayoutParams.MATCH_PARENT);
+        params.setMarginsRelative(0, _1dp * 10, 0, _1dp * 10);
+        border.setLayoutParams(params);
+        border.setBackgroundColor(Color.parseColor("#9E9E9E"));
+        border.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        border.setEnabled(false);
+        border.setFocusable(false);
+        border.setContentDescription(null);
+        return border;
+    }
+
     /**
      * Creates an "appear" animation for the specified view.
      *
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 58fb145..ef6e6c2 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -569,11 +569,12 @@
     /**
      * Clear any lock pattern or password.
      */
-    public void clearLock(int userHandle) {
+    public void clearLock(String savedCredential, int userHandle) {
         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
 
-        try {
-            getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, null, userHandle);
+        try{
+            getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
+                    userHandle);
         } catch (RemoteException e) {
             // well, we tried...
         }
@@ -758,7 +759,6 @@
     public void saveLockPassword(String password, String savedPassword, int quality,
             int userHandle) {
         try {
-            DevicePolicyManager dpm = getDevicePolicyManager();
             if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
                 throw new IllegalArgumentException("password must not be null and at least "
                         + "of length " + MIN_LOCK_PASSWORD_SIZE);
@@ -769,48 +769,55 @@
             getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
                     userHandle);
 
-            // Update the device encryption password.
-            if (userHandle == UserHandle.USER_SYSTEM
-                    && LockPatternUtils.isDeviceEncryptionEnabled()) {
-                if (!shouldEncryptWithCredentials(true)) {
-                    clearEncryptionPassword();
-                } else {
-                    boolean numeric = computedQuality
-                            == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-                    boolean numericComplex = computedQuality
-                            == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
-                    int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
-                            : StorageManager.CRYPT_TYPE_PASSWORD;
-                    updateEncryptionPassword(type, password);
-                }
-            }
-
-            // Add the password to the password history. We assume all
-            // password hashes have the same length for simplicity of implementation.
-            String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
-            if (passwordHistory == null) {
-                passwordHistory = "";
-            }
-            int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
-            if (passwordHistoryLength == 0) {
-                passwordHistory = "";
-            } else {
-                byte[] hash = passwordToHash(password, userHandle);
-                passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
-                // Cut it to contain passwordHistoryLength hashes
-                // and passwordHistoryLength -1 commas.
-                passwordHistory = passwordHistory.substring(0, Math.min(hash.length
-                        * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
-                        .length()));
-            }
-            setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
-            onAfterChangingPassword(userHandle);
+            addEncryptionPassword(password, computedQuality, userHandle);
+            updatePasswordHistory(password, userHandle);
         } catch (RemoteException re) {
             // Cant do much
             Log.e(TAG, "Unable to save lock password " + re);
         }
     }
 
+    private void addEncryptionPassword(String password, int quality, int userHandle) {
+        // Update the device encryption password.
+        if (userHandle == UserHandle.USER_SYSTEM
+                && LockPatternUtils.isDeviceEncryptionEnabled()) {
+            if (!shouldEncryptWithCredentials(true)) {
+                clearEncryptionPassword();
+            } else {
+                boolean numeric = quality == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+                boolean numericComplex = quality
+                        == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+                int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
+                        : StorageManager.CRYPT_TYPE_PASSWORD;
+                updateEncryptionPassword(type, password);
+            }
+        }
+    }
+
+    private void updatePasswordHistory(String password, int userHandle) {
+
+        // Add the password to the password history. We assume all
+        // password hashes have the same length for simplicity of implementation.
+        String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
+        if (passwordHistory == null) {
+            passwordHistory = "";
+        }
+        int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
+        if (passwordHistoryLength == 0) {
+            passwordHistory = "";
+        } else {
+            byte[] hash = passwordToHash(password, userHandle);
+            passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
+            // Cut it to contain passwordHistoryLength hashes
+            // and passwordHistoryLength -1 commas.
+            passwordHistory = passwordHistory.substring(0, Math.min(hash.length
+                    * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
+                    .length()));
+        }
+        setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
+        onAfterChangingPassword(userHandle);
+    }
+
     /**
      * Determine if the device supports encryption, even if it's set to default. This
      * differs from isDeviceEncrypted() in that it returns true even if the device is
diff --git a/core/java/com/android/internal/widget/WatchHeaderListView.java b/core/java/com/android/internal/widget/WatchHeaderListView.java
index 53fa7ab..7e91537 100644
--- a/core/java/com/android/internal/widget/WatchHeaderListView.java
+++ b/core/java/com/android/internal/widget/WatchHeaderListView.java
@@ -26,8 +26,7 @@
 import android.widget.HeaderViewListAdapter;
 
 import java.util.ArrayList;
-
-import com.android.internal.util.Predicate;
+import java.util.function.Predicate;
 
 public class WatchHeaderListView extends ListView {
     private View mTopPanel;
@@ -92,14 +91,13 @@
     }
 
     @Override
-    protected <T extends View> T findViewByPredicateTraversal(
-            Predicate<View> predicate, View childToSkip) {
+    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
         View v = super.findViewByPredicateTraversal(predicate, childToSkip);
         if (v == null && mTopPanel != null && mTopPanel != childToSkip
                 && !mTopPanel.isRootNamespace()) {
-            return (T) mTopPanel.findViewByPredicate(predicate);
+            return mTopPanel.findViewByPredicate(predicate);
         }
-        return (T) v;
+        return v;
     }
 
     @Override
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 407e69c..e237ce9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -216,7 +216,7 @@
     gCurRuntime->onStarted();
 }
 
-static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
+static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
 {
     gCurRuntime->onZygoteInit();
 }
@@ -230,19 +230,27 @@
 /*
  * JNI registration.
  */
-static const JNINativeMethod gMethods[] = {
-    { "nativeFinishInit", "()V",
-        (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
-    { "nativeZygoteInit", "()V",
-        (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
-    { "nativeSetExitWithoutCleanup", "(Z)V",
-        (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
-};
 
 int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
 {
+    const JNINativeMethod methods[] = {
+        { "nativeFinishInit", "()V",
+            (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
+        { "nativeSetExitWithoutCleanup", "(Z)V",
+            (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
+    };
     return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
-        gMethods, NELEM(gMethods));
+        methods, NELEM(methods));
+}
+
+int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
+{
+    const JNINativeMethod methods[] = {
+        { "nativeZygoteInit", "()V",
+            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
+    };
+    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
+        methods, NELEM(methods));
 }
 
 // ----------------------------------------------------------------------
@@ -1271,6 +1279,7 @@
 
 static const RegJNIRec gRegJNI[] = {
     REG_JNI(register_com_android_internal_os_RuntimeInit),
+    REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_android_os_SystemClock),
     REG_JNI(register_android_util_EventLog),
     REG_JNI(register_android_util_Log),
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index fadf8a4..6cf5ccf 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -30,6 +30,7 @@
 #include <binder/Parcel.h>
 #include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
+#include <hardware/gralloc1.h>
 #include <ui/GraphicBuffer.h>
 
 #include <private/gui/ComposerService.h>
@@ -96,10 +97,15 @@
         }
         return NULL;
     }
-    uint32_t grallocUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage, 0);
+    uint64_t producerUsage = 0;
+    uint64_t consumerUsage = 0;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage, 0, &producerUsage,
+            &consumerUsage);
     status_t error;
     sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, pixelFormat,
-            layers, grallocUsage, &error));
+            layers, producerUsage, consumerUsage,
+            std::string("HardwareBuffer pid [") + std::to_string(getpid()) +"]",
+            &error));
     if (buffer == NULL) {
         if (kDebugGraphicBuffer) {
             ALOGW("createGraphicBuffer() failed in HardwareBuffer.create()");
@@ -158,7 +164,7 @@
     jobject clazz, jlong nativeObject) {
     GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
     return android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
-            buffer->getUsage());
+            buffer->getUsage(), buffer->getUsage());
 }
 
 // ----------------------------------------------------------------------------
@@ -261,52 +267,58 @@
     }
 }
 
-uint32_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0,
-        uint64_t usage1) {
-    uint32_t bits = 0;
+void android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0,
+        uint64_t usage1, uint64_t* outProducerUsage,
+        uint64_t* outConsumerUsage) {
+    *outProducerUsage = 0;
+    *outConsumerUsage = 0;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ))
-        bits |= GRALLOC_USAGE_SW_READ_RARELY;
+        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN))
-        bits |= GRALLOC_USAGE_SW_READ_OFTEN;
+        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE))
-        bits |= GRALLOC_USAGE_SW_WRITE_RARELY;
+        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN))
-        bits |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE))
-        bits |= GRALLOC_USAGE_HW_TEXTURE;
+        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT))
-        bits |= GRALLOC_USAGE_HW_RENDER;
+        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
     // Not sure what this should be.
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0;
-    //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER) bits |= 0;
+    //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER))
+        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE))
-        bits |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
+        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER;
     if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT))
-        bits |= GRALLOC_USAGE_PROTECTED;
-
-    (void)usage1;
-
-    return bits;
+        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA))
+        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA;
 }
 
-uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(uint64_t usage0) {
+uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
+        uint64_t producerUsage, uint64_t consumerUsage) {
     uint64_t bits = 0;
-    if (containsBits(usage0, GRALLOC_USAGE_SW_READ_RARELY))
+    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ))
         bits |= AHARDWAREBUFFER_USAGE0_CPU_READ;
-    if (containsBits(usage0, GRALLOC_USAGE_SW_READ_OFTEN))
+    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN))
         bits |= AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
-    if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_RARELY))
+    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE))
         bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE;
-    if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_OFTEN))
+    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN))
         bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN;
-    if (containsBits(usage0, GRALLOC_USAGE_HW_TEXTURE))
+    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE))
         bits |= AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
-    if (containsBits(usage0, GRALLOC_USAGE_HW_RENDER))
+    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET))
         bits |= AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT;
-    if (containsBits(usage0, GRALLOC_USAGE_HW_VIDEO_ENCODER))
+    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER))
+        bits |= AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER;
+    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER))
         bits |= AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE;
-    if (containsBits(usage0, GRALLOC_USAGE_PROTECTED))
+    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_PROTECTED))
         bits |= AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT;
+    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA))
+        bits |= AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA;
 
     return bits;
 }
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index be3a87b..eaf9e91 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -1006,9 +1006,8 @@
     ALOGD("Native heap dump complete.\n");
 }
 
-
-static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz,
-    jint pid, jstring fileName)
+static void android_os_Debug_dumpNativeBacktraceToFileTimeout(JNIEnv* env, jobject clazz,
+    jint pid, jstring fileName, jint timeoutSecs)
 {
     if (fileName == NULL) {
         jniThrowNullPointerException(env, "file == null");
@@ -1031,7 +1030,7 @@
     if (lseek(fd, 0, SEEK_END) < 0) {
         fprintf(stderr, "lseek: %s\n", strerror(errno));
     } else {
-        dump_backtrace_to_file(pid, fd);
+        dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
     }
 
     close(fd);
@@ -1077,8 +1076,8 @@
             (void*)android_os_Debug_getProxyObjectCount },
     { "getBinderDeathObjectCount", "()I",
             (void*)android_os_Debug_getDeathObjectCount },
-    { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
-            (void*)android_os_Debug_dumpNativeBacktraceToFile },
+    { "dumpNativeBacktraceToFileTimeout", "(ILjava/lang/String;I)V",
+            (void*)android_os_Debug_dumpNativeBacktraceToFileTimeout },
     { "getUnreachableMemory", "(IZ)Ljava/lang/String;",
             (void*)android_os_Debug_getUnreachableMemory },
 };
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 905a85a..399dec8 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "GraphicsEnvironment"
 
-#include <gui/GraphicsEnv.h>
+#include <ui/GraphicsEnv.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include "core_jni_helpers.h"
 
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index d35ffbb..1f7efa1 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -127,18 +127,23 @@
         uint32_t flags,
         TransactCallback callback) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    bool isOneway = (flags & TF_ONE_WAY) != 0;
+    ScopedLocalRef<jobject> replyObj(env, nullptr);
+    sp<JHwParcel> replyContext = nullptr;
 
     ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env));
     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
             const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */);
 
-    ScopedLocalRef<jobject> replyObj(env, JHwParcel::NewObject(env));
 
-    sp<JHwParcel> replyContext =
-        JHwParcel::GetNativeContext(env, replyObj.get());
+    if (!isOneway) {
+        replyObj.reset(JHwParcel::NewObject(env));
 
-    replyContext->setParcel(reply, false /* assumeOwnership */);
-    replyContext->setTransactCallback(callback);
+        replyContext = JHwParcel::GetNativeContext(env, replyObj.get());
+
+        replyContext->setParcel(reply, false /* assumeOwnership */);
+        replyContext->setTransactCallback(callback);
+    }
 
     env->CallVoidMethod(
             mObject,
@@ -166,27 +171,29 @@
 
     status_t err = OK;
 
-    if (!replyContext->wasSent()) {
-        // The implementation never finished the transaction.
-        err = UNKNOWN_ERROR;  // XXX special error code instead?
+    if (!isOneway) {
+        if (!replyContext->wasSent()) {
+            // The implementation never finished the transaction.
+            err = UNKNOWN_ERROR;  // XXX special error code instead?
 
-        reply->setDataPosition(0 /* pos */);
+            reply->setDataPosition(0 /* pos */);
+        }
+
+        // Release all temporary storage now that scatter-gather data
+        // has been consolidated, either by calling the TransactCallback,
+        // if wasSent() == true or clearing the reply parcel (setDataOffset above).
+        replyContext->getStorage()->release(env);
+
+        // We cannot permanently pass ownership of "data" and "reply" over to their
+        // Java object wrappers (we don't own them ourselves).
+        replyContext->setParcel(
+                NULL /* parcel */, false /* assumeOwnership */);
+
     }
 
-    // Release all temporary storage now that scatter-gather data
-    // has been consolidated, either by calling the TransactCallback,
-    // if wasSent() == true or clearing the reply parcel (setDataOffset above).
-    replyContext->getStorage()->release(env);
-
-    // We cannot permanently pass ownership of "data" and "reply" over to their
-    // Java object wrappers (we don't own them ourselves).
-
     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
             NULL /* parcel */, false /* assumeOwnership */);
 
-    replyContext->setParcel(
-            NULL /* parcel */, false /* assumeOwnership */);
-
     return err;
 }
 
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index b2dee06..8590ecf 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -382,7 +382,7 @@
     s = nullptr;
 
     hidl_string tmp;
-    tmp.setToExternal(static_cast<const char *>(subBlob->data()), size);
+    tmp.setToExternal(static_cast<const char *>(subBlob->data()), size - 1);
 
     sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
     blob->write(offset, &tmp, sizeof(tmp));
diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp
index 75b898e..3f021ae 100644
--- a/core/jni/android_os_seccomp.cpp
+++ b/core/jni/android_os_seccomp.cpp
@@ -147,6 +147,9 @@
     // Needed for kernel to restart syscalls
     AllowSyscall(f, 128); // __NR_restart_syscall
 
+    // b/35034743
+    AllowSyscall(f, 267); // __NR_fstatfs64
+
     Trap(f);
 
     if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0)
@@ -206,6 +209,16 @@
     // already allowed.
     AllowSyscall(f, 85);  // __NR_readlink
 
+    // b/34908783
+    AllowSyscall(f, 250); // __NR_epoll_create
+
+    // b/34979910
+    AllowSyscall(f, 8);   // __NR_creat
+    AllowSyscall(f, 10);  // __NR_unlink
+
+    // b/35059702
+    AllowSyscall(f, 196); // __NR_lstat64
+
     Trap(f);
 
     return install_filter(f);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 5c65241..e2fc444 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -247,24 +247,42 @@
 
 static void DropCapabilitiesBoundingSet(JNIEnv* env) {
   for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-    // Keep CAP_SYS_PTRACE in our bounding set so crash_dump can gain it.
-    if (i == CAP_SYS_PTRACE) {
-      continue;
-    }
-
     int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
     if (rc == -1) {
       if (errno == EINVAL) {
         ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
               "your kernel is compiled with file capabilities support");
       } else {
+        ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
         RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed");
       }
     }
   }
 }
 
-static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+static void SetInheritable(JNIEnv* env, uint64_t inheritable) {
+  __user_cap_header_struct capheader;
+  memset(&capheader, 0, sizeof(capheader));
+  capheader.version = _LINUX_CAPABILITY_VERSION_3;
+  capheader.pid = 0;
+
+  __user_cap_data_struct capdata[2];
+  if (capget(&capheader, &capdata[0]) == -1) {
+    ALOGE("capget failed: %s", strerror(errno));
+    RuntimeAbort(env, __LINE__, "capget failed");
+  }
+
+  capdata[0].inheritable = inheritable;
+  capdata[1].inheritable = inheritable >> 32;
+
+  if (capset(&capheader, &capdata[0]) == -1) {
+    ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
+    RuntimeAbort(env, __LINE__, "capset failed");
+  }
+}
+
+static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective,
+                            uint64_t inheritable) {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
   capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -276,9 +294,12 @@
   capdata[1].effective = effective >> 32;
   capdata[0].permitted = permitted;
   capdata[1].permitted = permitted >> 32;
+  capdata[0].inheritable = inheritable;
+  capdata[1].inheritable = inheritable >> 32;
 
   if (capset(&capheader, &capdata[0]) == -1) {
-    ALOGE("capset(%" PRId64 ", %" PRId64 ") failed", permitted, effective);
+    ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted,
+          effective, inheritable, strerror(errno));
     RuntimeAbort(env, __LINE__, "capset failed");
   }
 }
@@ -532,6 +553,7 @@
       EnableKeepCapabilities(env);
     }
 
+    SetInheritable(env, permittedCapabilities);
     DropCapabilitiesBoundingSet(env);
 
     bool use_native_bridge = !is_system_server && (instructionSet != NULL)
@@ -604,7 +626,7 @@
         }
     }
 
-    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+    SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities);
 
     SetSchedulerPolicy(env);
 
diff --git a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
index 60e065c..a5d0596 100644
--- a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
+++ b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
@@ -40,12 +40,13 @@
       uint32_t format);
 
 /* Convert from AHARDWAREBUFFER_USAGE* flags to to gralloc usage flags. */
-extern uint32_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(
-      uint64_t usage0, uint64_t usage1);
+extern void android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+      uint64_t usage0, uint64_t usage1, uint64_t* outProducerUsage,
+      uint64_t* outConsumerUsage);
 
 /* Convert from gralloc usage flags to to AHARDWAREBUFFER_USAGE0* flags. */
 extern uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
-      uint64_t usage0);
+      uint64_t producerUsage, uint64_t consumerUsage);
 
 } // namespace android
 
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 9beae08..ba1d664 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -23,6 +23,7 @@
 import "frameworks/base/core/proto/android/service/appwidget.proto";
 import "frameworks/base/core/proto/android/service/fingerprint.proto";
 import "frameworks/base/core/proto/android/service/netstats.proto";
+import "frameworks/base/core/proto/android/service/notification.proto";
 import "frameworks/base/core/proto/android/providers/settings.proto";
 
 package android.os;
@@ -55,4 +56,5 @@
     android.service.NetworkStatsServiceDumpProto netstats = 3001;
     android.providers.settings.SettingsServiceDumpProto settings = 3002;
     android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
+    android.service.notification.NotificationServiceDumpProto notification = 3004;
 }
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 7674d7a..ee50c29 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -328,6 +328,7 @@
     SettingProto enable_cellular_on_boot = 283;
     SettingProto max_notification_enqueue_rate = 284;
     SettingProto cell_on = 285;
+    SettingProto network_recommendations_package = 286;
 }
 
 message SecureSettingsProto {
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
new file mode 100644
index 0000000..bc257e0
--- /dev/null
+++ b/core/proto/android/service/notification.proto
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.service.notification;
+
+option java_multiple_files = true;
+option java_outer_classname = "NotificationServiceProto";
+
+message NotificationServiceDumpProto {
+    repeated NotificationRecordProto records = 1;
+}
+
+message NotificationRecordProto {
+    string key = 1;
+    State state = 2;
+    int32 flags = 3;
+    string channelId = 4;
+    string sound = 5;
+    int32 sound_usage = 6;
+    bool can_vibrate = 7;
+    bool can_show_light = 8;
+    string group_key = 9;
+    int32 importance = 10;
+}
+
+enum State {
+    ENQUEUED = 0;
+
+    POSTED = 1;
+}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 11eb47b..5b5e61e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2365,6 +2365,11 @@
     <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by the CompanionDeviceManager to ensure that only the system can bind to it.
+         @hide -->
+    <permission android:name="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
          that only the system can bind to it.
          @hide -->
@@ -3215,6 +3220,11 @@
     <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by system apps when accessing restricted VR APIs.
+         <p>Protection level: signature -->
+    <permission android:name="android.permission.RESTRICTED_VR_ACCESS"
+        android:protectionLevel="signature|preinstalled" />
+
     <!-- Required to make calls to {@link android.service.vr.IVrManager}.
          @hide -->
     <permission android:name="android.permission.ACCESS_VR_MANAGER"
@@ -3242,6 +3252,10 @@
     <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
                 android:protectionLevel="signature" />
 
+    <!-- Allows an instant app to create foreground services. -->
+    <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
+        android:protectionLevel="signature|development|ephemeral|appop" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/drawable/btn_event_material.xml b/core/res/res/drawable/btn_event_material.xml
new file mode 100644
index 0000000..47c49cf
--- /dev/null
+++ b/core/res/res/drawable/btn_event_material.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+
+    <path
+        android:fillColor="#90ffffff"
+        android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
+2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
+    <path android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/btn_keyboard_key_material.xml b/core/res/res/drawable/btn_keyboard_key_material.xml
new file mode 100644
index 0000000..14a9492f
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_material.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+
+    <path
+        android:fillColor="#90ffffff"
+        android:pathData="M20 5H4c-1.1 0-1.99 .9 -1.99 2L2 17c0 1.1 .9 2 2 2h16c1.1 0 2-.9
+2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0
+3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9
+7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z" />
+    <path
+        android:pathData="M0 0h24v24H0zm0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/core/res/res/drawable/resolver_icon_placeholder.xml
similarity index 69%
copy from core/res/res/values-ldrtl/dimens.xml
copy to core/res/res/drawable/resolver_icon_placeholder.xml
index 807c042..049cfee 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/core/res/res/drawable/resolver_icon_placeholder.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+    <solid android:color="#10000000"/>
+    <size android:width="36dp" android:height="36dp"/>
+</shape>
\ No newline at end of file
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
index 70833d6..8b95f9f 100644
--- a/core/res/res/layout-land/time_picker_material.xml
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -15,28 +15,17 @@
      limitations under the License.
 -->
 
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layoutDirection="ltr">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
 
-    <!-- Provides a background for the time layout that extends into the button bar area. -->
-    <com.android.internal.widget.DrawingSpace
+    <LinearLayout
         android:id="@+id/time_header"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_column="@dimen/time_picker_column_start_material"
-        android:layout_row="0"
-        android:layout_rowSpan="3"
-        android:layout_gravity="center|fill"
-        android:layoutDirection="locale" />
-
-    <RelativeLayout
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_column="@dimen/time_picker_column_start_material"
-        android:layout_row="1"
-        android:layout_gravity="center|fill"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:gravity="center"
         android:paddingStart="?attr/dialogPreferredPadding"
         android:paddingEnd="?attr/dialogPreferredPadding">
 
@@ -44,10 +33,8 @@
             android:id="@+id/time_layout"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layout_centerInParent="true"
             android:paddingTop="@dimen/timepicker_radial_picker_top_margin"
-            android:layout_marginBottom="-12dp">
+            android:orientation="horizontal">
 
             <!-- The hour should always be to the left of the separator,
                  regardless of the current locale's layout direction. -->
@@ -125,38 +112,71 @@
                 android:includeFontPadding="false"
                 android:button="@null" />
         </RadioGroup>
-    </RelativeLayout>
+    </LinearLayout>
 
-    <ViewStub
-        android:id="@id/topPanel"
-        android:layout="@layout/alert_dialog_title_material"
+    <TextView
+        android:visibility="gone"
+        android:id="@+id/input_header"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:paddingStart="@dimen/dialog_padding_material"
+        android:paddingEnd="@dimen/dialog_padding_material"
+        android:paddingTop="20dp"
+        android:paddingBottom="20dp"
+        android:includeFontPadding="false"
+        android:textAppearance="@style/TextAppearance.Material.TimePicker.InputHeader"
+        android:text="@string/time_picker_header_text"/>
+
+    <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_column="@dimen/time_picker_column_end_material"
-        android:layout_row="0"
-        android:layout_gravity="top|fill_horizontal"
-        android:layoutDirection="locale" />
+        android:orientation="vertical">
 
-    <android.widget.RadialTimePickerView
-        android:id="@+id/radial_picker"
-        android:layout_width="@dimen/timepicker_radial_picker_dimen"
-        android:layout_height="@dimen/timepicker_radial_picker_dimen"
-        android:layout_column="@dimen/time_picker_column_end_material"
-        android:layout_row="1"
-        android:layout_rowWeight="1"
-        android:layout_gravity="center|fill"
-        android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
-        android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
-        android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin"
-        android:layoutDirection="locale" />
+        <android.widget.RadialTimePickerView
+            android:id="@+id/radial_picker"
+            android:layout_width="@dimen/timepicker_radial_picker_dimen"
+            android:layout_height="@dimen/timepicker_radial_picker_dimen"
+            android:layout_gravity="center|fill"
+            android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
+            android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
+            android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin"
+            android:layoutDirection="locale" />
 
-    <ViewStub
-        android:id="@id/buttonPanel"
-        android:layout="@layout/alert_dialog_button_bar_material"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_column="@dimen/time_picker_column_end_material"
-        android:layout_row="2"
-        android:layout_gravity="bottom|fill_horizontal"
-        android:layoutDirection="locale" />
-</GridLayout>
+        <android.widget.TextInputTimePickerView
+            android:id="@+id/input_mode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingStart="?attr/dialogPreferredPadding"
+            android:paddingEnd="?attr/dialogPreferredPadding"
+            android:visibility="gone" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <ImageButton
+                android:id="@+id/toggle_mode"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="12dp"
+                android:layout_marginEnd="12dp"
+                android:padding="12dp"
+                android:background="?attr/selectableItemBackgroundBorderless"
+                android:tint="?attr/colorControlNormal"
+                android:src="@drawable/btn_keyboard_key_material"
+                android:contentDescription="@string/time_picker_text_input_mode_description" />
+            <Space
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
+            <ViewStub
+                android:id="@id/buttonPanel"
+                android:layout="@layout/alert_dialog_button_bar_material"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layoutDirection="locale" />
+        </LinearLayout>
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index d8dd447..7dee2af 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -53,8 +53,7 @@
                    android:visibility="gone"
                    android:scaleType="fitCenter"
                    android:layout_below="@id/profile_button"
-                   android:layout_alignParentLeft="true"
-                   />
+                   android:layout_alignParentLeft="true"/>
         <TextView android:id="@+id/title"
                   android:layout_height="wrap_content"
                   android:layout_width="wrap_content"
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 02cd8cd..bed80ed 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -24,6 +24,7 @@
     android:layout_width="match_parent">
 
     <LinearLayout
+        android:id="@+id/prefs_container"
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="0px"
@@ -61,8 +62,7 @@
                 android:layout_width="0px"
                 android:layout_height="match_parent"
                 android:layout_weight="@integer/preferences_right_pane_weight"
-                android:orientation="vertical"
-                android:visibility="gone" >
+                android:orientation="vertical">
 
             <!-- Breadcrumb inserted here, in certain screen sizes. In others, it will be an
                 empty layout or just padding, and PreferenceActivity will put the breadcrumbs in
diff --git a/core/res/res/layout/preference_list_content_material.xml b/core/res/res/layout/preference_list_content_material.xml
index 1bc527e..37b4119 100644
--- a/core/res/res/layout/preference_list_content_material.xml
+++ b/core/res/res/layout/preference_list_content_material.xml
@@ -24,6 +24,7 @@
     android:layout_width="match_parent">
 
     <LinearLayout
+        android:id="@+id/prefs_container"
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="0px"
@@ -64,8 +65,7 @@
                 android:layout_width="0px"
                 android:layout_height="match_parent"
                 android:layout_weight="@integer/preferences_right_pane_weight"
-                android:orientation="vertical"
-                android:visibility="gone" >
+                android:orientation="vertical">
 
             <!-- Breadcrumb inserted here, in certain screen sizes. In others, it will be an
                 empty layout or just padding, and PreferenceActivity will put the breadcrumbs in
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 02dc2ed..8101183 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -45,6 +45,7 @@
                 android:layout_marginStart="16dp"
                 android:layout_marginEnd="16dp"
                 android:layout_marginTop="20dp"
+                android:src="@drawable/resolver_icon_placeholder"
                 android:scaleType="fitCenter" />
 
             <TextView
diff --git a/core/res/res/layout/time_picker_material.xml b/core/res/res/layout/time_picker_material.xml
index 37a7384..7597379 100644
--- a/core/res/res/layout/time_picker_material.xml
+++ b/core/res/res/layout/time_picker_material.xml
@@ -34,4 +34,53 @@
         android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
         android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
         android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin" />
+    <TextView
+        android:visibility="gone"
+        android:id="@+id/input_header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="@dimen/dialog_padding_material"
+        android:paddingEnd="@dimen/dialog_padding_material"
+        android:paddingTop="20dp"
+        android:paddingBottom="20dp"
+        android:includeFontPadding="false"
+        android:fontFamily="sans-serif-medium"
+        android:textSize="34sp"
+        android:textColor="@color/white"
+        android:text="@string/time_picker_header_text"/>
+    <android.widget.TextInputTimePickerView
+        android:id="@+id/input_mode"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingEnd="?attr/dialogPreferredPadding"
+        android:visibility="gone" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <ImageButton
+            android:id="@+id/toggle_mode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginStart="12dp"
+            android:layout_marginEnd="12dp"
+            android:padding="12dp"
+            android:background="?attr/selectableItemBackgroundBorderless"
+            android:tint="?attr/colorControlNormal"
+            android:src="@drawable/btn_keyboard_key_material"
+            android:contentDescription="@string/time_picker_text_input_mode_description" />
+        <Space
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+        <ViewStub
+            android:id="@id/buttonPanel"
+            android:layout="@layout/alert_dialog_button_bar_material"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layoutDirection="locale" />
+    </LinearLayout>
+
 </LinearLayout>
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
new file mode 100644
index 0000000..f17b80e
--- /dev/null
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <TextView
+        android:id="@+id/top_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="26dp"
+        android:layout_marginBottom="8dp"
+        android:text="@string/time_picker_prompt_label"
+        android:textAppearance="@style/TextAppearance.Material.TimePicker.PromptLabel" />
+
+    <RelativeLayout
+        android:id="@+id/input_block"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/top_label"
+        android:layoutDirection="ltr">
+        <EditText
+            android:id="@+id/input_hour"
+            android:layout_width="50dp"
+            android:layout_height="wrap_content"
+            android:inputType="number"
+            android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+        <TextView
+            android:id="@+id/label_hour"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/input_hour"
+            android:layout_alignStart="@id/input_hour"
+            android:text="@string/time_picker_hour_label"/>
+
+        <TextView
+            android:id="@+id/input_separator"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignEnd="@id/input_hour"
+            android:layout_alignBaseline="@id/input_hour"
+            android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+
+        <EditText
+            android:id="@+id/input_minute"
+            android:layout_width="50dp"
+            android:layout_height="wrap_content"
+            android:layout_alignBaseline="@id/input_hour"
+            android:layout_toEndOf="@id/input_separator"
+            android:inputType="number"
+            android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+        <TextView
+            android:id="@+id/label_minute"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/input_minute"
+            android:layout_alignStart="@id/input_minute"
+            android:text="@string/time_picker_minute_label"/>
+
+        <TextView
+            android:visibility="invisible"
+            android:id="@+id/label_error"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/input_hour"
+            android:layout_alignStart="@id/input_hour"
+            android:textColor="?attr/textColorError"
+            android:text="@string/time_picker_input_error" />
+    </RelativeLayout>
+    <Spinner
+        android:id="@+id/am_pm_spinner"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@id/input_block"
+        android:layout_alignParentEnd="true"/>
+
+</merge>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 9be3635..46d0745 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Beheer die vertoonskerm se zoemvlak en posisionering."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Voer gebare uit"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tik, swiep, knyp en ander gebare uitvoer."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Vingerafdrukgebare"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan gebare wat op die toestel se vingerafdruksensor uitgevoer word, vasvang"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"deaktiveer of verander statusbalk"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Laat die program toe om die statusbalk te deaktiveer en stelselikone by te voeg of te verwyder."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"wees die statusbalk"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tik vir meer opsies."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-ontfouter gekoppel"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tik om USB-ontfouting te deaktiveer."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Kies om USB-ontfouting te deaktiveer."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Neem tans foutverslag …"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deel foutverslag?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deel tans foutverslag …"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Nuus en tydskrifte"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kaarte en navigasie"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktiwiteit"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Toestelberging"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 41dff04..45206873 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"የማሳያውን የማጉያ ደረጃ እና አቀማመጥ ይቆጣጠሩ።"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"የጣት ምልክቶችን ያከናውኑ"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"መታ ማድረግ፣ ማንሸራተት፣ መቆንጠጥ እና ሌሎች የጣት ምልክቶችን ማከናወን ይችላል።"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"የጣት አሻራ ምልክቶች"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"በመሣሪያዎቹ የጣት አሻራ ዳሳሽ ላይ የተከናወኑ የጣት ምልክቶችን መያዝ ይችላል።"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"የሁኔቴ አሞሌ አቦዝን ወይም ቀይር"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"የስርዓት አዶዎችን ወደ ሁኔታ አሞሌ ላለማስቻል ወይም ለማከል እና ለማስወገድ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"የሁኔታ አሞሌ መሆን"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"ለተጨማሪ አማራጮች መታ ያድርጉ።"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB አድስ ተያይዟል"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"የዩኤስቢ ማረሚያን ለማሰናከል መታ ያድርጉ።"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ማረሚያ ላለማንቃት ምረጥ።"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"የሳንካ ሪፖርትን በመውሰድ ላይ…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"የሳንካ ሪፖርት ይጋራ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"የሳንካ ሪፖርትን በማጋራት ላይ…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"ዜና እና መጽሔቶች"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"ካርታዎች እና ዳሰሳ"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ውጤታማነት"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"የመሣሪያ ማከማቻ"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 07e1699..95118c2 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -290,6 +290,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"يمكنك التحكم في مستوى التكبير/التصغير للشاشة وتحديد الموضع."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"تنفيذ إيماءات"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"يمكن النقر والتمرير بسرعة والتصغير وتنفيذ إيماءات أخرى."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"إيماءات بصمات الإصبع"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"يمكن أن تلتقط الإيماءات التي تم تنفيذها على مستشعر بصمات الإصبع في الأجهزة."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"تعطيل شريط الحالة أو تعديله"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"للسماح للتطبيق بتعطيل شريط الحالة أو إضافة رموز نظام وإزالتها."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"العمل كشريط للحالة"</string>
@@ -1226,6 +1228,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"انقر للحصول على المزيد من الخيارات."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏تم توصيل تصحيح أخطاء USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏انقر لتعطيل تصحيح أخطاء USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏اختيار تعطيل تصحيح أخطاء USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"جارٍ الحصول على تقرير الخطأ…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"هل تريد مشاركة تقرير الخطأ؟"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"جارٍ مشاركة تقرير الخطأ…"</string>
@@ -1813,4 +1816,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"الأخبار والمجلات"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"الخرائط والتنقل"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"الإنتاجية"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"السعة التخزينية للجهاز"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index ebc4eed..cf377b2 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekran yaxınlaşdırma səviyyəsi və yerləşdirməsinə nəzarət edin."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Jestlər ilə əməliyyat aparın"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Digər jestlərə tıklaya, sürüşdürə və əməliyyat apara bilərsiniz."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Barmaq izi işarələri"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Cihazların barmaq izi sensorunda olan işarələri əldə edə bilər"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"status panelini deaktivləşdir və ya dəyişdir"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Tətbiqə status panelini deaktiv etməyə və ya sistem ikonalarını əlavə etmək və ya silmək imkanı verir."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"status paneli edin"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Əlavə seçimlər üçün tıklayın."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB sazlama qoşuludur"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB debaqı deaktivasiya etmək üçün tıklayın."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USb debaqı deaktivasiya etməyi seçin."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Baq hesabatı verilir..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Baq hesabatı paylaşılsın?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Baq hesabatı paylaşılır..."</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Xəbər və Jurnallar"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Xəritə və Naviqasiya"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Məhsuldarlıq"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Cihaz yaddaşı"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 810ed0f..e56d938 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -281,6 +281,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Upravlja nivoom zumiranja prikaza i određivanjem položaja."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obavljanje pokreta"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može da dodiruje, lista, skuplja prikaz i obavlja druge pokrete."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pokreti za otisak prsta"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Može da registruje pokrete na senzoru za otisak prsta na uređaju."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmena statusne trake"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Dozvoljava aplikaciji da onemogući statusnu traku ili da dodaje i uklanja sistemske ikone."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"funkcionisanje kao statusna traka"</string>
@@ -1166,6 +1168,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za još opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izaberite da biste onemogućili otklanjanja grešaka sa USB-a."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izveštaj o grešci se generiše…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li da podelite izveštaj o grešci?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deli se izveštaj o grešci…"</string>
@@ -1720,4 +1723,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Novosti i časopisi"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mape i navigacija"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivnost"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Memorijski prostor uređaja"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 7ad40c4..6383c39 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Кіраваць маштабам дысплэя і пазіцыянаваннем."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Выконваць жэсты"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можна кранаць, праводзіць пальцам, маштабаваць шчыпком, а таксама выконваць іншыя жэсты."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жэсты адбіткаў пальцаў"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Можа распазнаваць жэсты на сканеры адбіткаў пальцаў прылады."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"адключаць ці змяняць радок стану"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"быць панэллю стану"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Дакраніцеся, каб атрымаць іншыя параметры."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Адладка па USB падключана"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Дакраніцеся, каб адключыць адладку па USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Выберыце, каб адключыць адладку USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Стварэнне справаздачы пра памылку…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Падзяліцца справаздачай пра памылку?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Перадача справаздачы пра памылку..."</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Навіны і часопісы"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Карты і навігацыя"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Прадукцыйнасць"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Сховішча на прыладзе"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 9afed47..1238e2c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управление на нивото на мащаба и позиционирането на дисплея."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Извършване на жестове"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можете да докосвате, да прекарвате пръст, да събирате пръсти и да извършвате други жестове."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жестове за отпечатък"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Може да улавя жестовете, извършени върху сензора за отпечатъци на устройството."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"деактивиране или промяна на лентата на състоянието"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Разрешава на приложението да деактивира лентата на състоянието или да добавя и премахва системни икони."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"изпълняване на ролята на лента на състоянието"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Докоснете за още опции."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняване на грешки през USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Докоснете, за да деактивирате отстраняването на грешки през USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изберете, за да деактивирате отстраняването на грешки през USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Сигналът за програмна грешка се извлича…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели ли сигналът за програмна грешка?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Сигналът за програмна грешка се споделя…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Новини и списания"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Карти и навигация"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Производителност"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Хранилище на устройството"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 6522537..9bedf58 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -63,8 +63,8 @@
     <string name="needPuk2" msgid="4526033371987193070">"সিম কার্ড অবরোধ মুক্ত করতে PUK2 লিখুন৷"</string>
     <string name="enablePin" msgid="209412020907207950">"অসফল, সিম/RUIM লক সক্ষম করুন৷"</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
-      <item quantity="one">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM লক হয়ে যাবে৷</item>
-      <item quantity="other">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM লক হয়ে যাবে৷</item>
+      <item quantity="one">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম লক হয়ে যাবে৷</item>
+      <item quantity="other">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম লক হয়ে যাবে৷</item>
     </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -255,7 +255,7 @@
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"ক্যালেন্ডার"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"আপনার ক্যালেন্ডারে অ্যাক্সেস"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS বার্তাগুলি পাঠাতে এবং দেখতে"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"এসএমএসগুলি পাঠাতে এবং দেখতে"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"সঞ্চয়স্থান"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"আপনার ডিভাইসে ফটো, মিডিয়া এবং ফাইলগুলিতে অ্যাক্সেস"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"মাইক্রোফোন"</string>
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"প্রদর্শনের জুমের স্তর এবং অবস্থান নির্ধারন নিয়ন্ত্রণ করুন৷"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"অঙ্গভঙ্গির কাজগুলি সম্পাদন করুন"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"আলতো চাপ দেওয়া, সোয়াইপ, পিঞ্চ করা এবং অন্যান্য অঙ্গভঙ্গির কাজগুলি সম্পাদন করতে পারবেন৷"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ফিঙ্গারপ্রিন্ট সেন্সরের উপর করা অঙ্গভঙ্গিগুলি"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সরের উপর আঙ্গুলের অঙ্গভঙ্গি ক্যাপচার করতে পারে।"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"স্থিতি দন্ড নিষ্ক্রিয় অথবা সংশোধন করে"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"অ্যাপ্লিকেশানকে স্থিতি দন্ড অক্ষম করতে এবং সিস্টেম আইকনগুলি সরাতে দেয়৷"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"স্থিতি দন্ডে থাকুন"</string>
@@ -291,7 +293,7 @@
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"আউটগোয়িং কলগুলি পুনঃচালিত করুন"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"অ্যাপ্লিকেশানকে কল চলাকালীন অন্য একটি নম্বরে কল পুনঃনির্দেশ বা কলটি একসথে বন্ধ করার সাথে ডায়াল করা নম্বরটি দেখতে দেয়৷"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"পাঠ্য বার্তা পান (SMS)"</string>
-    <string name="permdesc_receiveSms" msgid="6424387754228766939">"অ্যাপ্লিকেশানটিকে SMS বার্তা প্রাপ্ত করার এবং প্রক্রিয়া করার অনুমতি দেয়৷ এর মানে হল অ্যাপ্লিকেশানটি আপনার ডিভাইস থেকে পাঠানো বার্তাগুলিকে পর্যবেক্ষণ করতে পারে এবং মুছতে পারে সেগুলিকে আপনাকে না দেখিয়ে৷"</string>
+    <string name="permdesc_receiveSms" msgid="6424387754228766939">"অ্যাপ্লিকেশানটিকে এসএমএস প্রাপ্ত করার এবং প্রক্রিয়া করার অনুমতি দেয়৷ এর মানে হল অ্যাপ্লিকেশানটি আপনার ডিভাইস থেকে পাঠানো বার্তাগুলিকে পর্যবেক্ষণ করতে পারে এবং মুছতে পারে সেগুলিকে আপনাকে না দেখিয়ে৷"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"পাঠ্য বার্তা পান (MMS)"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"অ্যাপ্লিকেশানটিকে MMS বার্তা প্রাপ্ত করার এবং প্রক্রিয়া করার অনুমতি দেয়৷ এর মানে হল অ্যাপ্লিকেশানটি আপনার ডিভাইস থেকে পাঠানো বার্তাগুলিকে পর্যবেক্ষণ করতে পারে এবং মুছতে পারে সেগুলিকে আপনাকে না দেখিয়ে৷"</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"সেল সম্প্রচার বার্তা পড়ুন"</string>
@@ -299,7 +301,7 @@
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"গ্রাহক হিসাবে নেওয়া ফিডগুলি পড়ে"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"অ্যাপ্লিকেশানকে বর্তমানে সিঙ্ক করা ফিডগুলির সম্পর্কে বিবরণ পেতে দেয়৷"</string>
     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS পাঠানো ও দেখা,আপনি কি পরিচিতি কে এগুলি করার অনুমতি দেবেন?"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"অ্যাপ্লিকেশানটিকে SMS বার্তাগুলি পাঠাতে অনুমতি দেয়৷ এর জন্য অপ্রত্যাশিত চার্জ কাটা হতে পারে৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার নিশ্চিতকরণ ছাড়া বার্তা পাঠানোর মাধ্যমে আপনাকে অর্থ চার্জ করতে পারে৷"</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"অ্যাপ্লিকেশানটিকে এসএমএসগুলি পাঠাতে অনুমতি দেয়৷ এর জন্য অপ্রত্যাশিত চার্জ কাটা হতে পারে৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার নিশ্চিতকরণ ছাড়া বার্তা পাঠানোর মাধ্যমে আপনাকে অর্থ চার্জ করতে পারে৷"</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"আপনার পাঠ্য বার্তা পড়ুন (SMS বা MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"এই অ্যাপটি আপনার ট্যাবলেটে সংরক্ষিত সমস্ত SMS (পাঠ্য) বার্তা পড়তে পারে৷"</string>
     <string name="permdesc_readSms" product="tv" msgid="5796670395641116592">"এই অ্যাপটি আপনার টিভিতে সংরক্ষিত সমস্ত SMS (পাঠ্য) বার্তা পড়তে পারে৷"</string>
@@ -370,7 +372,7 @@
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ভলিউম এবং যেখানে স্পিকার আউটপুট সামগ্রী হিসাবে ব্যবহৃত হয় সেই সব ক্ষেত্রে গ্লোবাল অডিও সেটিংসের সংশোধন করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷"</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"অডিও রেকর্ড"</string>
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"এই অ্যাপটি মাইক্রোফোন ব্যবহার করে যে কোনো সময় অডিও রেকর্ড করতে পারে৷"</string>
-    <string name="permlab_sim_communication" msgid="2935852302216852065">"SIM এ আদেশগুলি পাঠান"</string>
+    <string name="permlab_sim_communication" msgid="2935852302216852065">"সিম এ আদেশগুলি পাঠান"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"অ্যাপ্লিকেশানটিকে সিম কার্ডে কমান্ডগুলি পাঠানোর অনুমতি দেয়৷ এটি খুবই বিপজ্জনক৷"</string>
     <string name="permlab_camera" msgid="3616391919559751192">"ছবি এবং ভিডিও তোলে"</string>
     <string name="permdesc_camera" msgid="5392231870049240670">"এই অ্যাপটি যে কোনো সময় ক্যামেরা ব্যবহার করে ছবি তুলতে বা ভিডিও রেকর্ড করতে পারে৷"</string>
@@ -479,8 +481,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"অ্যাপ্লিকেশানকে SD কার্ডে লেখার অনুমতি দেয়৷"</string>
     <string name="permlab_use_sip" msgid="2052499390128979920">"SIP কল করুন/গ্রহণ করুন"</string>
     <string name="permdesc_use_sip" msgid="2297804849860225257">"অ্যাপ্লিকেশানকে SIP কল করতে ও গ্রহণ করতে অনুমতি দেয়।"</string>
-    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"নতুন টেলিকম SIM সংযোগগুলির নিবন্ধন"</string>
-    <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"অ্যাপ্লিকেশানটিকে নতুন টেলিকম SIM সংযোগগুলি নিবন্ধিত করতে অনুমোদিত করে৷"</string>
+    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"নতুন টেলিকম সিম সংযোগগুলির নিবন্ধন"</string>
+    <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"অ্যাপ্লিকেশানটিকে নতুন টেলিকম সিম সংযোগগুলি নিবন্ধিত করতে অনুমোদিত করে৷"</string>
     <string name="permlab_register_call_provider" msgid="108102120289029841">"নতুন টেলিকম সংযোগগুলির নিবন্ধন"</string>
     <string name="permdesc_register_call_provider" msgid="7034310263521081388">"নতুন টেলিকম সংযোগ নিবন্ধিত করতে অ্যাপ্লিকেশানটিকে অনুমোদিত করে৷"</string>
     <string name="permlab_connection_manager" msgid="1116193254522105375">"টেলিকম সংযোগগুলি পরিচালনা করুন"</string>
@@ -692,7 +694,7 @@
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"মুখের সাহায্যে আনলক করার প্রচেষ্টা যতবার করা যায় তার সীমা পেরিয়ে গেছে"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"কোনো সিম কার্ড নেই"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ট্যাবলেটের মধ্যে কোনো সিম কার্ড নেই৷"</string>
-    <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"টিভির মধ্যে কোনো SIM কার্ড নেই৷"</string>
+    <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"টিভির মধ্যে কোনো সিম কার্ড নেই৷"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ফোনের মধ্যে কোনো সিম কার্ড নেই৷"</string>
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"একটি সিম কার্ড ঢোকান৷"</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"সিম কার্ডটি অনুপস্থিত বা পাঠযোগ্য নয়৷ একটি সিম কার্ড ঢোকান৷"</string>
@@ -1104,8 +1106,8 @@
     <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"আপনার টিভি <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত থাকার সময় ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে৷"</string>
     <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ফোনটি যখন <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত হবে তখন এটি ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে"</string>
     <string name="select_character" msgid="3365550120617701745">"অক্ষর ঢোকান"</string>
-    <string name="sms_control_title" msgid="7296612781128917719">"SMS বার্তা পাঠানো হচ্ছে"</string>
-    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অনেকগুলি SMS বার্তা পাঠাচ্ছে৷ আপনি কি এই অ্যাপ্লিকেশানটিকে বার্তা পাঠানো চালিয়ে যাওয়ার অনুমতি দিতে চান?"</string>
+    <string name="sms_control_title" msgid="7296612781128917719">"এসএমএস পাঠানো হচ্ছে"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অনেকগুলি এসএমএস পাঠাচ্ছে৷ আপনি কি এই অ্যাপ্লিকেশানটিকে বার্তা পাঠানো চালিয়ে যাওয়ার অনুমতি দিতে চান?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"অনুমতি দিন"</string>
     <string name="sms_control_no" msgid="625438561395534982">"আস্বীকার করুন"</string>
     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; এ একটি বার্তা পাঠাতে চায়৷"</string>
@@ -1123,10 +1125,10 @@
     <string name="sim_added_title" msgid="3719670512889674693">"সিম কার্ড যোগ করা হয়েছে"</string>
     <string name="sim_added_message" msgid="7797975656153714319">"সেলুলার নেটওয়ার্ক অ্যাক্সেস করতে আপনার ডিভাইস পুনর্সূচনা করুন"</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"পুনর্সূচনা"</string>
-    <string name="carrier_app_dialog_message" msgid="7066156088266319533">"যাতে আপনার নতুন SIM সঠিকভাবে কাজ করে, তার জন্য আপনাকে আপনার পরিষেবা প্রদানকারীর থেকে একটি অ্যাপ্লিকেশান ইনস্টল করতে এবং খুলতে হবে৷"</string>
+    <string name="carrier_app_dialog_message" msgid="7066156088266319533">"যাতে আপনার নতুন সিম সঠিকভাবে কাজ করে, তার জন্য আপনাকে আপনার পরিষেবা প্রদানকারীর থেকে একটি অ্যাপ্লিকেশান ইনস্টল করতে এবং খুলতে হবে৷"</string>
     <string name="carrier_app_dialog_button" msgid="7900235513678617329">"অ্যাপ্লিকেশানটি পান"</string>
     <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"এখনই নয়"</string>
-    <string name="carrier_app_notification_title" msgid="8921767385872554621">"নতুন SIM ঢোকানো হয়েছে"</string>
+    <string name="carrier_app_notification_title" msgid="8921767385872554621">"নতুন সিম ঢোকানো হয়েছে"</string>
     <string name="carrier_app_notification_text" msgid="1132487343346050225">"এটিকে সেট আপ করতে আলতো চাপুন"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"সময় সেট করুন"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"তারিখ সেট করুন"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"আরো বিকল্পের জন্য আলতো চাপুন৷"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ডিবাগিং সংযুক্ত হয়েছে"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ডিবাগিং অক্ষম করতে আলতো চাপুন৷"</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ত্রুটির প্রতিবেদন নেওয়া হচ্ছে..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ত্রুটির প্রতিবেদন শেয়ার করবেন?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ত্রুটির প্রতিবেদন শেয়ার করা হচ্ছে..."</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"খবর ও পত্রিকাগুলি"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"মানচিত্র ও নেভিগেশান"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"উৎপাদনশীলতা"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ডিভাইসের সঞ্চয়স্থান"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c6d70f3..66ef19a33 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -281,6 +281,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolira stepen uvećanja prikaza na ekranu i podešavanje položaja."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Praviti pokrete"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može dodirivati, prevlačiti, hvatati prstima i praviti druge pokrete."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pokreti otiska prsta"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Moguće je zabilježiti pokrete na senzoru za otisak prsta uređaja."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili mijenjanje statusne trake"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Dozvoljava aplikaciji onemogućavanje statusne trake ili dodavanje i uklanjanje sistemskih ikona."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"funkcioniranje u vidu statusne trake"</string>
@@ -1168,6 +1170,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za više opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka putem uređaja spojenog na USB je uspostavljeno"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da onemogućite otklanjanje grešaka putem uređaja spojenog na USB."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Prijem izvještaja o grešci..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Podijeliti izvještaj o grešci?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvještaja o grešci..."</string>
@@ -1722,4 +1726,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Vijesti i časopisi"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mape i navigacija"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivnost"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Memorija uređaja"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index eebe75f..b01f382 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el nivell i el posicionament del zoom de la pantalla."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Utilitza gestos"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Pot tocar, lliscar, pessigar i utilitzar altres gestos."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos amb les empremtes digitals"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Captura gestos realitzats en el sensor d\'empremtes digitals del dispositiu."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra d\'estat"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permet que l\'aplicació desactivi la barra d\'estat o afegeixi i elimini icones del sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"aparèixer a la barra d\'estat"</string>
@@ -950,7 +952,7 @@
     <string name="inputMethod" msgid="1653630062304567879">"Mètode d\'introducció de text"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Accions de text"</string>
     <string name="email" msgid="4560673117055050403">"Correu electrònic"</string>
-    <string name="dial" msgid="2275093056198652749">"Marcatge"</string>
+    <string name="dial" msgid="2275093056198652749">"Telèfon"</string>
     <string name="map" msgid="5441053548030107189">"Mapa"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"L\'espai d\'emmagatzematge s\'està esgotant"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Toca per veure més opcions."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuració USB activada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca per desactivar la depuració USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecciona per desactivar la depuració USB"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"S\'està creant l\'informe d\'errors…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vols compartir l\'informe d\'errors?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"S\'està compartint l\'informe d\'errors…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Notícies i revistes"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapes i navegació"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivitat"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Emmagatzematge del dispositiu"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 68cc583..b8717d5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Určuje umístění a úroveň přiblížení displeje."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Provádění gest"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Může provádět gesta klepnutí, přejetí, stažení prstů a další."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesta otiskem prstu"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dokáže rozpoznat gesta zadaná na snímači otisků prstů."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"zakázání či změny stavového řádku"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikaci zakázat stavový řádek nebo přidat či odebrat systémové ikony."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vydávání se za stavový řádek"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Klepnutím zobrazíte další možnosti."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes USB připojeno"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Klepnutím zakážete ladění USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vyberte, chcete-li zakázat ladění USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Vytváření zprávy o chybě…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Sdílet zprávu o chybě?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sdílení zprávy o chybě…"</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Zprávy a časopisy"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapy a navigace"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivita"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Úložiště zařízení"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index f2b6be9..ebcd48e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér skærmens zoomniveau og position."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Udfør bevægelser"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, stryge, knibe sammen og udføre andre bevægelser."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingeraftryksbevægelser"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan registrere bevægelser, der foretages på enhedernes fingeraftrykslæser."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"deaktiver eller rediger statuslinje"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Tillader, at appen kan deaktivere statusbjælken eller tilføje og fjerne systemikoner."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vær statusbjælken"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tryk for at se flere muligheder."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryk for at deaktivere fejlretning via USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vælg for at deaktivere USB-fejlretning."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Opretter fejlrapport…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele fejlrapporten?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler fejlrapport…"</string>
@@ -1395,7 +1398,7 @@
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Forkert pinkode"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%1$d</xliff:g> sekunder."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn dit mønster"</string>
-    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM-kort"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"Angiv adgangskode"</string>
     <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-kortet er nu deaktiveret. Indtast PUK-koden for at fortsætte. Kontakt mobiloperatøren for at få flere oplysninger."</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Aviser og blade"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kort og navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Lagerplads på enheden"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 5ba5464..7e31748 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Legt die Zoom-Stufe des Displays und die Zoom-Position auf dem Display fest."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Bewegungen möglich"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Bewegungen möglich."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Bewegungen auf dem Fingerabdrucksensor"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Erfasst Bewegungen auf dem Fingerabdrucksensor des Geräts."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ermöglicht der App, die Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Statusleiste darstellen"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Für weitere Optionen tippen."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging aktiviert"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Zum Deaktivieren von USB-Debugging tippen."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB-Debugging deaktivieren: auswählen"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Fehlerbericht wird abgerufen…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Fehlerbericht teilen?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Fehlerbericht wird geteilt…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Nachrichten &amp; Zeitschriften"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Karten &amp; Navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Effizienz"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Gerätespeicher"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 409b573..7458e04 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ελέγξτε το επίπεδο ζουμ και τη θέση της οθόνης."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Εκτέλεση κινήσεων"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Επιτρέπει το πάτημα, την ολίσθηση, το πλησίασμα και άλλες κινήσεις."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Κινήσεις δακτυλικών αποτυπωμάτων"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Μπορεί να αναγνωρίσει κινήσεις που εκτελούνται στον αισθητήρα δακτυλικών αποτυπωμάτων των συσκευών."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποιεί ή να τροποποιεί την γραμμή κατάστασης"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Επιτρέπει στην εφαρμογή να απενεργοποιεί τη γραμμή κατάστασης ή να προσθέτει και να αφαιρεί εικονίδια συστήματος."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ορίζεται ως γραμμή κατάστασης"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Πατήστε για περισσότερες επιλογές."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Πατήστε για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Λήψη αναφοράς σφάλματος…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Κοινή χρήση αναφοράς σφάλματος;"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Κοινή χρήση αναφοράς σφάλματος…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Ειδήσεις και περιοδικά"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Χάρτες και πλοήγηση"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Παραγωγικότητα"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Αποθηκευτικός χώρος συσκευής"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 02860cf..107f247 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Device storage"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 02860cf..107f247 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Device storage"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 02860cf..107f247 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Device storage"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index bd3ac31..2749b35 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Usar gestos"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permite presionar, deslizar, pellizcar y usar otros gestos."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos del sensor de huellas digitales"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Captura los gestos que se hacen en el sensor de huellas digitales de los dispositivos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o que agregue y elimine íconos del sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Presiona para ver más opciones."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración por USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Presiona para inhabilitar la depuración por USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para desactivar la depuración por USB"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Realizando un informe de errores…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Noticias y revistas"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapas y navegación"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productividad"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Almacenamiento del dispositivo"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 26f6005..bdb1381 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Puedes tocar y pellizcar la pantalla, deslizar el dedo y hacer otros gestos."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de huellas digitales"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Puede capturar los gestos realizados en el sensor de huellas digitales del dispositivo."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"inhabilitar o modificar la barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o añada y elimine iconos del sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
@@ -949,12 +951,9 @@
     <string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Método de introducción de texto"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
-    <!-- no translation found for email (4560673117055050403) -->
-    <skip />
-    <!-- no translation found for dial (2275093056198652749) -->
-    <skip />
-    <!-- no translation found for map (5441053548030107189) -->
-    <skip />
+    <string name="email" msgid="4560673117055050403">"Correo electrónico"</string>
+    <string name="dial" msgid="2275093056198652749">"Marcar"</string>
+    <string name="map" msgid="5441053548030107189">"Mapa"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no funcionen."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Comprueba que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -1149,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Toca para ver más opciones."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para inhabilitar la depuración USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para inhabilitar la depuración USB"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de errores…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
@@ -1205,10 +1205,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite que una aplicación consulte sesiones de instalación para ver detalles sobre instalaciones de paquetes activos."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"solicitar instalación de paquetes"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Permite a una aplicación solicitar la instalación de paquetes."</string>
-    <!-- no translation found for permlab_requestDeletePackages (1703686454657781242) -->
-    <skip />
-    <!-- no translation found for permdesc_requestDeletePackages (3406172963097595270) -->
-    <skip />
+    <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"solicitar eliminación de paquetes"</string>
+    <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Permite a una aplicación solicitar la eliminación de paquetes."</string>
     <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"solicitar permiso para ignorar las optimizaciones de la batería"</string>
     <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permite que una aplicación solicite permiso para ignorar las optimizaciones de la batería."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Da dos toques para acceder al control de zoom."</string>
@@ -1694,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Noticias y revistas"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapas y navegación"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productividad"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Almacenamiento del dispositivo"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 30e73d8..5b532b4 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Saate juhtida ekraani suumitaset ja asendit."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Liigutuste tegemine"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Saate puudutada, pühkida, sõrmi kokku-lahku liigutada ja teisi liigutusi teha."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Sõrmejälje liigutused"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Teil on võimalik jäädvustada liigutused, mis on tehtud seadmete sõrmejäljeanduri abil."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"keela või muuda olekuriba"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Võimaldab rakendusel keelata olekuriba või lisada ja eemaldada süsteemiikoone."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"olekuribana kuvamine"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Puudutage lisavalikute nägemiseks."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-silumine ühendatud"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Puudutage USB-silumise keelamiseks."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Valige USB silumise keelamiseks"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Veaaruande võtmine …"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kas jagada veaaruannet?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Veaaruande jagamine …"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Uudised ja ajakirjad"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kaardid ja navigeerimine"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktiivsus"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Seadme salvestusruum"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index a49f94f..afb0a9c 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolatu pantailaren zoom-maila eta kokapena."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Keinuak egin"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Hatz-marken keinuak"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Gailuaren hatz-marken sentsorean egindako keinuak antzeman ditzake."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Desgaitu edo aldatu egoera-barra"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Egoera-barra desgaitzea edo sistema-ikonoak gehitzea edo kentzea baimentzen die aplikazioei."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Bihurtu egoera-barra"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Sakatu aukera gehiago ikusteko."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Sakatu USB arazketa desgaitzeko."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Akatsen txostena sortzen…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Akatsen txostena partekatu nahi duzu?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Akatsen txostena partekatzen…"</string>
@@ -1232,7 +1236,7 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Horma-papera"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Aldatu horma-papera"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Jakinarazpenak hautemateko zerbitzua"</string>
-    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Errealitate birtualeko hautemailea"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"EB hautemailea"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Baldintza-hornitzailea"</string>
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Jakinarazpenen sailkapen-zerbitzua"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN eginbidea aktibatuta"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Albisteak eta aldizkariak"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapak eta nabigazioa"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktibitatea"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Gailuaren memoria"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 3880caa..1e1c8fa 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"سطح و موقعیت بزرگ‌نمایی نمایشگر را کنترل کنید."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"اجرای اشاره‌ها"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"می‌توانید ضربه بزنید، انگشتتان را تند بکشید، انگشتانتان را به هم نزدیک یا از هم دور کنید و اشاره‌های دیگری اجرا کنید."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"اشاره‌های اثر انگشت"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"می‌تواند اشاره‌های انجام‌شده روی حسگر اثرانگشت دستگاه‌ها را ثبت کند."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"غیرفعال کردن یا تغییر نوار وضعیت"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"‏به برنامه اجازه می‎دهد تا نوار وضعیت را غیرفعال کند یا نمادهای سیستم را اضافه یا حذف کند."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"نوار وضعیت باشد"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"برای گزینه‌های بیشتر ضربه بزنید."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏اشکال‌زدایی USB متصل شد"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏برای غیرفعال کردن اشکال‌زدایی USB ضربه بزنید."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏انتخاب کنید تا رفع عیب USB غیرفعال شود."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"درحال گرفتن گزارش اشکال…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"گزارش اشکال به اشتراک گذاشته شود؟"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"درحال اشتراک‌گذاری گزارش اشکال…‏"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"اخبار و مجله"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"نقشه و پیمایش"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"بهره‌وری"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"حافظه دستگاه"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f0afbc8..c3c2c65 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Hallinnoi näytön zoomaustasoa ja asettelua."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Eleiden käyttäminen"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Lupa napauttaa, pyyhkäistä, nipistää ja käyttää muita eleitä."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Sormenjälkieleet"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Voi tallentaa laitteen sormenjälkitunnistimella tehtyjä eleitä."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"poista tilapalkki käytöstä tai muokkaa tilapalkkia"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Antaa sovelluksen poistaa tilapalkin käytöstä ja lisätä tai poistaa järjestelmäkuvakkeita."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"sijaita tilapalkissa"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Näet lisää vaihtoehtoja napauttamalla."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Poista USB-vianetsintä käytöstä napauttamalla."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Luodaan virheraporttia…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Jaetaanko virheraportti?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Jaetaan virheraporttia…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Uutiset ja lehdet"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kartat ja navigointi"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Tuottavuus"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Laitteen tallennustila"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 65609f4..7e051c9 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Peut toucher, balayer, pincer et effectuer d\'autres gestes."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestes sur le capteur d\'empreintes digitales"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Peut capturer des gestes effectués sur le capteur d\'empreintes digitales des appareils."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"désactiver ou modifier la barre d\'état"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"servir de barre d\'état"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Touchez pour afficher plus d\'options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Touchez pour désactiver le débogage USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création d\'un rapport de bogue en cours..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bogue?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bogue en cours..."</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Actualités et magazines"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Cartes et navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivité"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Mémoire de l\'appareil"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 66fb5b4..b8fcf28 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permet d\'appuyer sur l\'écran, de le balayer, de le pincer et d\'effectuer d\'autres gestes."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestes avec l\'empreinte digitale"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Peut enregistrer des gestes effectués sur le lecteur d\'empreinte digitale de l\'appareil."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"remplacer la barre d\'état"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Appuyez ici pour plus d\'options."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Appuyez ici pour désactiver le débogage USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création du rapport de bug…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bug ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bug…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Actualités et magazines"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Plans et navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivité"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Mémoire de l\'appareil"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 9b335a1..5d316f6 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nivel do zoom e o posicionamento da pantalla"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar xestos"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Podes tocar, pasar o dedo, beliscar e realizar outros xestos."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Xestos de impresión dixital"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode rexistrar os xestos realizados no sensor de impresión dixital dos dispositivos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar a barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite á aplicación desactivar a barra de estado ou engadir e eliminar as iconas do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"actuar como a barra de estado"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Toca para ver máis opcións."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para desactivar a depuración de erros de USB."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de erros…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Queres compartir o informe de erros?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartindo informe de erros..."</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Noticias e revistas"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegación"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Almacenamento do dispositivo"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 2bd3e41..b5c243b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"પ્રદર્શનનું ઝૂમ સ્તર અને સ્થિતિનિર્ધારણ નિયંત્રિત કરો."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"હાવભાવ કરો"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ટૅપ, સ્વાઇપ, પિંચ કરી અને અન્ય હાવભાવ કરી શકે છે."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ફિંગરપ્રિન્ટ હાવભાવો"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ઉપકરણોનાં ફિંગરપ્રિન્ટ સેન્સર પર ભજવેલા હાવભાવ કૅપ્ચર કરી શકે છે."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"સ્થિતિ બાર અક્ષમ કરો અથવા સંશોધિત કરો"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"એપ્લિકેશનને સ્થિતિ બાર અક્ષમ કરવાની અથવા સિસ્ટમ આયકન્સ ઉમેરવા અને દૂર કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"સ્થિતિ બાર થાઓ"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"વધુ વિકલ્પો માટે ટૅપ કરો."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ડીબગિંગ કનેક્ટ થયું."</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ડીબગિંગ અક્ષમ કરવા માટે ટૅપ કરો."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"બગ રિપોર્ટ લઈ રહ્યાં છે…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"બગ રિપોર્ટ શેર કરીએ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"બગ રિપોર્ટ શેર કરી રહ્યાં છે…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"સમાચાર અને સામાયિકો"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"નકશા અને નેવિગેશન"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ઉત્પાદકતા"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ઉપકરણ સ્ટૉરેજ"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6300703..f2c3d43 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शन का ज़ूम स्‍तर और स्‍थिति निर्धारण नियंत्रित करें."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"हावभाव निष्पादित करें"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"इस सेवा के द्वारा टैप किया जा सकता है, स्वाइप किया जा सकता है, पिंच किया जा सकता है और अन्य हावभाव निष्पादित किए जा सकते हैं."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"फ़िंगरप्रिंट हावभाव"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"डिवाइस फ़िंगरप्रिंट सेंसर पर किए गए हावभाव कैप्चर किए जा सकते हैं."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"स्‍थिति बार अक्षम या बदलें"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"ऐप्स  को स्थिति बार अक्षम करने या सिस्‍टम आइकन को जोड़ने या निकालने देता है."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"स्‍थिति बार होने दें"</string>
@@ -951,7 +953,7 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"लेख क्रियाएं"</string>
     <string name="email" msgid="4560673117055050403">"ईमेल करें"</string>
     <string name="dial" msgid="2275093056198652749">"डायल करें"</string>
-    <string name="map" msgid="5441053548030107189">"नक्शा"</string>
+    <string name="map" msgid="5441053548030107189">"मानचित्र"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"मेमोरी स्‍थान समाप्‍त हो रहा है"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टम के लिए पर्याप्त मेमोरी नहीं है. सुनिश्चित करें कि आपके पास 250MB का खाली स्थान है और फिर से प्रारंभ करें."</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"अधिक विकल्पों के लिए टैप करें."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डीबग करना अक्षम करने के लिए टैप करें."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डीबग करना अक्षम करने के लिए चुनें."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट प्राप्त की जा रही है…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्ट साझा करें?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्ट साझा की जा रही है…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"समाचार और पत्रिकाएं"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"मानचित्र और मार्गदर्शक"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"उत्पादकता"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"डिवाइस में जगह"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index ee3ab30..11864c6 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -281,6 +281,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolira razinu zumiranja i položaj zaslona."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvođenje pokreta"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može dodirnuti, prijeći prstom, spojiti prste i izvoditi druge pokrete."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pokreti za otisak prsta"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Može snimati pokrete izvršene na senzoru otiska prsta na uređaju."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmjena trake statusa"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikaciji omogućuje onemogućavanje trake statusa ili dodavanje i uklanjanje sistemskih ikona."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"biti traka statusa"</string>
@@ -1166,6 +1168,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za više opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za otklanjanje pogrešaka USB-om"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje pogrešaka putem USB-a."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Odaberite da biste onemogućili rješavanje programske pogreške na USB-u."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izrada izvješća o programskoj pogrešci…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li podijeliti izvješće o programskoj pogrešci?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvješća o programskoj pogrešci…"</string>
@@ -1720,4 +1723,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Vijesti i časopisi"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Karte i navigacija"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivnost"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Pohrana na uređaju"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 943dbc0..4c6d440 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"A kijelző nagyítási/kicsinyítési szintjének és pozíciójának vezérlése"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kézmozdulatok végrehajtása"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Koppintás, ujjak gyors csúsztatása és összehúzása, illetve egyéb kézmozdulatok végrehajtása."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Kézmozdulatok az ujjlenyomat-érzékelőn"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Érzékeli az ujjlenyomat-érzékelőn végzett kézmozdulatokat."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"állapotsor kikapcsolása vagy módosítása"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Lehetővé teszi az alkalmazás számára az állapotsor kikapcsolását, illetve rendszerikonok hozzáadását és eltávolítását."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"az állapotsor szerepének átvétele"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Koppintson a további beállítások megjelenítéséhez."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Koppintson az USB fejlesztő mód kikapcsolásához."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Válassza ezt az USB hibakeresés kikapcsolásához."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hibajelentés készítése…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Megosztja a hibajelentést?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hibajelentés megosztása…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Hírlapok és folyóiratok"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Térképek és navigáció"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Irodai alkalmazások"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Eszköztárhely"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 7c579d1..276a326 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ցուցասարքի մասշտաբավորման և դիրքավորման կառավարում:"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Կատարել ժեստեր"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Կարող է հպել, թերթել, պտղունցել և կատարել այլ ժեստեր:"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Մատնահետքերի սկաների ժեստեր"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Կարող է նկարահանել մատնահետքերի սկաների վրա կատարվող ժեստերը"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"անջատել կամ փոփոխել կարգավիճակի գոտին"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Թույլ է տալիս հավելվածին անջատել կարգավիճակի գոտին կամ ավելացնել ու հեռացնել համակարգի պատկերակները:"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"լինել կարգավիճակի գոտի"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Հպեք՝ USB վրիպազերծումն անջատելու համար:"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Ընտրել` USB կարգաբերումը կասեցնելու համար:"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Վրիպակի զեկույցի ստեղծում…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Տրամադրե՞լ վրիպակի զեկույցը:"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Վրիպակի զեկույցի տրամադրում…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Նորություններ և ամսագրեր"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Քարտեզներ և նավարկում"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Աշխատանք"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Սարքի հիշողություն"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b9771d6..839fc04 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Mengontrol tingkat zoom dan pemosisian layar."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Melakukan isyarat"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggesek, mencubit, dan melakukan isyarat lainnya."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestur sidik jari"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dapat merekam gestur yang dilakukan di sensor sidik jari perangkat."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"nonaktifkan atau ubah bilah status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Mengizinkan apl menonaktifkan bilah status atau menambah dan menghapus ikon sistem."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"jadikan bilah status"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Ketuk untuk opsi lainnya."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB terhubung"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Ketuk untuk menonaktifkan debug USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk menonaktifkan debugging USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan bug…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bagikan laporan bug?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Membagikan laporan bug..."</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Berita &amp; Majalah"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Peta &amp; Navigasi"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitas"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Penyimpanan perangkat"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 775c50e..1e2beb0 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Stjórnaðu aðdrætti og afstöðu skjásins."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Nota bendingar"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Getur ýtt, strokið, fært fingur saman og gert ýmsar aðrar bendingar."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingrafarabendingar"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Getur fangað bendingar sem eru gerðar á fingrafaraskynjara tækisins."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"slökkva á eða breyta stöðustiku"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Leyfir forriti að slökkva á stöðustikunni eða bæta við og fjarlægja kerfistákn."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vera stöðustikan"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Ýttu til að sjá fleiri valkosti."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-villuleit tengd"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Ýttu til að slökkva á USB-villuleit."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Tekur við villutilkynningu…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deila villutilkynningu?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deilir villutilkynningu..."</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Fréttir og tímarit"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kort og leiðsögn"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Aðstoð"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Geymslurými tækis"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index cb4769c..0b7820e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlla il livello di zoom e la posizione del display."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Esegui gesti"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Consente di toccare, far scorrere, pizzicare ed eseguire altri gesti."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesti con sensore di impronte digitali"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"È in grado di rilevare i gesti compiuti con il sensore di impronte digitali dei dispositivi."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ruolo di barra di stato"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tocca per altre opzioni."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tocca per disattivare il debug USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleziona per disattivare il debug USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Recupero della segnalazione di bug…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Condividere la segnalazione di bug?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Condivisione della segnalazione di bug…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Notizie e riviste"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Maps e Navigatore"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produttività"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Memoria dispositivo"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d33cd08..4361ff2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"קבע את המרחק מהתצוגה ואת מיקום התצוגה."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ביצוע תנועות"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"יכול להקיש, להחליק, לעשות תנועת צביטה ולבצע תנועות אחרות."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"תנועות"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"אפשרות לזהות תנועות בזמן נגיעה בחיישן טביעות האצבע של המכשיר"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"השבת או שנה את שורת המצב"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"מאפשר לאפליקציה להשבית את שורת המצב או להוסיף ולהסיר סמלי מערכת."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"להיות שורת הסטטוס"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"הקש לקבלת אפשרויות נוספות."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏ניפוי באגים של USB מחובר"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏הקש כדי להשבית ניפוי באגים של USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏בחר להשבית ניפוי באגים ב-USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"עיבוד דוח על באג..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"האם לשתף דוח על באג?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"שיתוף דוח על באג…"</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"חדשות וכתבי עת"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"מפות וניווט"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"פרודוקטיביות"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"שטח האחסון במכשיר"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 3992e6e..f3a22ce 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"画面のズームレベルと位置を制御します。"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"操作の実行"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"タップ、スワイプ、ピンチ、その他の操作を行えます。"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指紋認証センサーでの操作"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"端末の指紋認証センサーで行われた操作をキャプチャできます。"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"ステータスバーの無効化や変更"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"ステータスバーの無効化、システムアイコンの追加や削除をアプリに許可します。"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ステータスバーへの表示"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"タップしてその他のオプションを表示します。"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"タップして USB デバッグを無効にします。"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USBデバッグを無効にする場合に選択します。"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"バグレポートを取得しています…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"バグレポートを共有しますか?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"バグレポートの共有中…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"ニュース&雑誌"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"地図&ナビ"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"仕事効率化"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"端末のストレージ"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 1fb7d13..9d3b288 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ეკრანის მასშტაბირების დონისა და პოზიციის მართვა."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ჟესტების შესრულება"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"შეუძლია შეხება, გადაფურცვლა, მასშტაბირება და სხვა ჟესტების შესრულება."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"თითის ანაბეჭდის ჟესტები"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"შეუძლია აღბეჭდოს მოწყობილობის თითის ანაბეჭდის სენსორზე განხორციელებული ჟესტები."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"სტატუსის ზოლის გათიშვა ან ცვლილება"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"აპს შეეძლება სტატუსების ზოლის გათიშვა და სისტემის ხატულების დამატება/წაშლა."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"სტატუსის ზოლის ჩანაცვლება"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"შეეხეთ დამატებითი ვარიანტების სანახავად."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB გამართვა შეერთებულია"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"შეეხეთ USB-გამართვის გასათიშად."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"მონიშნეთ რათა შეწყვიტოთ USB-ის გამართვა"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის შექმნა…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"გსურთ ხარვეზის შესახებ ანგარიშის გაზიარება?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გაზიარება…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"ახალი ამბები და ჟურნალები"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"რუკები და ნავიგაცია"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"პროდუქტიულობა"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"მოწყობილობის მეხსიერება"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 87958c7..b168b6f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Дисплейдің масштабтау деңгейін және орналастыруды басқару."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Қимылдарды орындау"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Түртуге, сырғытуға, қысуға және басқа қимылдарды орындауға болады."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Саусақ ізі датчигіндегі қимылдар"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Құрылғының саусақ ізі датчигінде орындалған қимылдарды сақтайды"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"күйін көрсету тақтасын өшіру немесе өзгерту"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Қолданбаға күй жолағын өшіруге немесе жүйелік белгішелерді қосуға және жоюға рұқсат береді."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"күй жолағы болу"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Қосымша опциялар үшін түртіңіз."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB жөндеу қосылған"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB түзетуін өшіру үшін түртіңіз."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Қате туралы есеп алынуда…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Қате туралы есепті бөлісу керек пе?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Қате туралы есеп бөлісілуде…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Газеттер және журналдар"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Карта және навигация"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Өнімділік"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Құрылғы жады"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index f92eff5..0a57834 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"គ្រប់គ្រងការកំណត់ទីតាំង និងកម្រិតពង្រីករបស់អេក្រង់"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ធ្វើកាយវិការ"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"អាចប៉ះ អូស ច្បិច និងធ្វើកាយវិការផ្សេងទៀត"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ចលនា​ស្នាមម្រាមដៃ"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"អាចថត​ចលនា​ដែលមាន​សកម្មភាព​នៅលើ​ឧបករណ៍​ចាប់​ស្នាម​ម្រាមដៃ​របស់ឧបករណ៍។"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"បិទ ឬ​កែ​របារ​ស្ថានភាព"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"ឲ្យ​កម្មវិធី​បិទ​របារ​ស្ថានភាព ឬ​បន្ថែម និង​លុប​រូប​តំណាង​ប្រព័ន្ធ។"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ធ្វើជារបារស្ថានភាព"</string>
@@ -1148,6 +1150,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"ប៉ះសម្រាប់ជម្រើសជាច្រើនទៀត"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"បាន​ភ្ជាប់​ការ​កែ​កំហុស​យូអេសប៊ី"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"ប៉ះដើម្បីបិទដំណើរការកែកំហុសយូអេសប៊ី"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ជ្រើស​ ដើម្បី​បិទ​ការ​កែ​កំហុស​យូអេសប៊ី។"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"កំពុងទទួលយករបាយការណ៍កំហុស…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ចែករំលែករបាយការណ៍កំហុសឬ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"កំពុងចែករំលែករបាយកំហុស…"</string>
@@ -1691,4 +1694,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"ព័ត៌មាន និង​ទស្សនាវដ្ដី"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"ផែនទី និង​ការ​រុករក"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ផលិត​ភាព"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ទំហំផ្ទុកឧបករណ៍"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 5c53b1c..07400f5 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ಪ್ರದರ್ಶನದ ಝೂಮ್ ಮಟ್ಟ ಮತ್ತು ಸ್ಥಾನ ನಿರ್ಧಾರವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ಗೆಸ್ಚರ್‌ಗಳನ್ನು ಮಾಡಿ"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ಟ್ಯಾಪ್ ಮಾಡಬಹುದು, ಸ್ವೈಪ್ ಮಾಡಬಹುದು, ಪಿಂಚ್ ಮಾಡಬಹುದು ಮತ್ತು ಇತರ ಗೆಸ್ಚರ್‌ಗಳನ್ನು ಮಾಡಬಹುದು."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್‌ ಸೂಚಕಗಳು"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ಸಾಧನದ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್‌ನಲ್ಲಿ ನಡೆಸಿದ ಸೂಚಕಗಳನ್ನು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ ಇಲ್ಲವೇ ಮಾರ್ಪಡಿಸಿ"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಅಥವಾ ಸೇರಿಸಲು ಮತ್ತು ಸಿಸ್ಟಂ ಐಕಾನ್‌ಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಾಗಿರಲು"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ದೋಷದ ವರದಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚುವುದೇ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"ಸುದ್ದಿ ಮತ್ತು ನಿಯತಕಾಲಿಕೆಗಳು"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"ನಕ್ಷೆಗಳು ಮತ್ತು ನ್ಯಾವಿಗೇಶನ್"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ಉತ್ಪಾದಕತೆ"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ಸಾಧನ ಸಂಗ್ರಹಣೆ"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ca70e45..b74094e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"디스플레이의 확대/축소 수준 및 위치를 제어합니다."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"동작 실행"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"탭, 스와이프, 확대/축소 및 기타 동작을 실행할 수 있습니다."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"지문 동작"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"기기 지문 센서에서 동작을 캡처합니다."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"상태 표시줄 사용 중지 또는 수정"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"앱이 상태 표시줄을 사용중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 허용합니다."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"상태 표시줄에 위치"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"옵션을 더 보려면 탭하세요."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB 디버깅을 사용하지 않으려면 탭하세요."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB 디버깅을 사용하지 않으려면 선택합니다."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"버그 보고서 가져오는 중..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"버그 보고서를 공유하시겠습니까?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"버그 신고서 공유 중..."</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"뉴스/잡지"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"지도/내비게이션"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"생산성"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"기기 저장용량"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 94b84f2..7b1d126 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Экрандагы сүрөттүн өлчөмүн өзгөртүү жана жайгаштыруу."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Жаңсоолорду аткаруу"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Таптап, серпип, чымчып жана башка жаңсоолорду аткара алат."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Манжа изинин жаңсоолору"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Түзмөктөрдөгү манжа изинин сенсорунда жасалган жаңсоолорду жаздырып алат."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"абал тилкесин өчүрүү же өзгөртүү"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Колдонмого абал тилкесин өчүрүү же тутум сүрөтчөлөрүн кошуу же алып салуу мүмкүнчүлүгүн берет."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"абал тилкесинин милдетин аткаруу"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Кошумча параметрлерди ачуу үчүн таптап коюңуз."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB аркылуу мүчүлүштүктөрдү оңдоо туташтырылган"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB арклуу мүчүлштктрдү жоюну өчр үчн тийп коюңуз."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Мүчүлүштүк тууралуу баяндама бөлүшүлсүнбү?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Мүчүлүштүк тууралуу баяндама бөлүшүлүүдө…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Жаңылыктар жана журналдар"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Карталар жана чабыттоо"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Өндүрүш категориясы"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Түзмөктүн сактагычы"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 816eea2..5d7b4c3 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ຄວບຄຸມລະດັບການຊູມ ແລະການວາງຕຳແໜ່ງຂອງຈໍສະແດງຜົນ."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ດຳເນີນທ່າທາງຕ່າງໆ"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ສາມາດແຕະ, ປັດນີ້ວມື, ຢິບນິ້ວມື ແລະ ດຳເນີນທ່າທາງອື່ນ."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ທ່າທາງລາຍນິ້ວມື"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ສາມາດບັນທຶກທ່າທາງທີ່ເກີດຂຶ້ນໃນອຸປະກອນເຊັນເຊີລາຍນິ້ວມືໄດ້."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"ປິດການນນຳໃຊ້ ຫຼື ແກ້ໄຂແຖບສະຖານະ"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"ອະນຸຍາດໃຫ້ແອັບຯປິດການເຮັດວຽກຂອງແຖບສະຖານະ ຫຼືເພີ່ມ ແລະລຶບໄອຄອນລະບົບອອກໄດ້."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ເປັນ​ແຖບ​ສະ​ຖາ​ນະ"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"ແຕະເພື່ອເບິ່ງຕົວເລືອກເພີ່ມເຕີມ."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"ເຊື່ອມຕໍ່ການດີບັ໊ກຜ່ານ USB ແລ້ວ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"ແຕະເພື່ອປິດການດີບັກຜ່ານ USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ເລືອກເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ກຳລັງຂໍລາຍງານຂໍ້ຜິດພາດ…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ແບ່ງປັນລາຍງານບັນຫາບໍ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ກຳລັງແບ່ງປັນລາຍງານບັນຫາ…"</string>
@@ -1202,8 +1205,8 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພລິ​ເຄ​ຊັນ​ອ່ານ​ເຊດ​ຊັນ​ການ​ຕິດ​ຕັ້ງ​ໄດ້. ນີ້​ຈະ​ອະ​ນຸ​ຍາດ​ໃຫ້​ມັນ​ເບິ່ງ​ເຫັນ​ລາຍ​ລະ​ອຽດ​ກ່ຽວ​ກັບ​ການ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ​ທີ່​ເຮັດ​​ວຽກ​ຢູ່​ໄດ້."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ຂໍ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ຂອງ​ການ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ."</string>
-    <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"request delete packages"</string>
-    <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ຂອງ​ການ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ."</string>
+    <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"ຮ້ອງຂໍການລຶບແພັກເກດ"</string>
+    <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຮ້ອງຂໍການລຶບແພັກເກດ."</string>
     <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ຖາມເພື່ອໃຫ້ເພີກເສີຍການປັບແຕ່ງແບັດເຕີຣີ"</string>
     <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ອະນຸຍາດໃຫ້ແອັບຖາມສິດອະນຸຍາດເພື່ອເພີກເສີຍຕໍ່ການປັບແຕ່ງແບັດເຕີຣີສຳລັບແອັບນັ້ນ."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ແຕະສອງເທື່ອເພື່ອຄວບຄຸມການຊູມ"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"News &amp; Magazines"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Maps &amp; Navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ຜະລິດຕະພາບ"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ບ່ອນຈັດເກັບຂໍ້ມູນອຸປະກອນ"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 837134c..89ac3f2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Valdykite ekrano mastelio keitimo lygį ir pozicijos nustatymą."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Veiksmai gestais"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Galima paliesti, perbraukti, suimti ir atlikti kitus veiksmus gestais."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Kontrolinio kodo gestai"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Gali užfiksuoti gestus, atliktus naudojant įrenginio kontrolinio kodo jutiklį."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"išjungti ar keisti būsenos juostą"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Leidžiama programai neleisti būsenos juostos arba pridėti ir pašalinti sistemos piktogramas."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"būti būsenos juosta"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Palieskite, kad būtų rodoma daugiau parinkčių."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB derinimas prijungtas"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Palieskite, kad išjungtumėte USB derinimą."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pasirinkite, kas išjungtumėte USB derinimą."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Pateikiamas pranešimas apie riktą…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bendrinti pranešimą apie riktą?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bendrinamas pranešimas apie riktą..."</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Naujienos ir žurnalai"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Žemėlapiai ir navigacija"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktyvumas"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Įrenginio saugykla"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 7510e77..5163334 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -281,6 +281,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolējiet displeja tālummaiņas līmeni un pozicionēšanu."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Žestu izpilde"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Atbalsta pieskaršanos, vilkšanu, savilkšanu un citus žestus."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Pirksta nospieduma žesti"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Var uztvert žestus ierīces pirksta nospieduma sensorā."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"atspējot vai pārveidot statusa joslu"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ļauj lietotnei atspējot statusa joslu vai pievienot un noņemt sistēmas ikonas."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Būt par statusa joslu"</string>
@@ -1166,6 +1168,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Pieskarieties, lai skatītu citas iespējas."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Pieskarieties, lai atspējotu USB atkļūdošanu."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Atlasiet, lai atspējotu USB atkļūdošanu."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Notiek kļūdas pārskata izveide…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vai kopīgot kļūdas pārskatu?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Notiek kļūdas pārskata kopīgošana…"</string>
@@ -1720,4 +1723,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Ziņas un žurnāli"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kartes un navigācija"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitāte"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Ierīces krātuve"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0e3862f..66d5387 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Контролирајте го нивото на зумирање и позиционирање на екранот."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Користете движења"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Може да допрете, повлечете, штипнете и да користите други движења."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Движења за отпечатоци"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Може да сними движења што се направени на сензорот за отпечатоци на уредите."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"оневозможи или измени статусна лента"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Дозволува апликацијата да ја оневозможи статусната лента или да додава или отстранува системски икони."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"да стане статусна лента"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Допрете за повеќе опции."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Поврзано е отстранување грешки преку УСБ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Допрете за да се оневозможи отстранувањето грешки преку USB."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Се зема извештајот за грешки…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели извештајот за грешки?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Се споделува извештај за грешки…"</string>
@@ -1691,4 +1695,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Вести и списанија"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Карти и навигација"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Продуктивност"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Простор на уредот"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index da97cf5..bb5455d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ഡിസ്പ്ലേയുടെ സൂം നിലയും പൊസിഷനിംഗും നിയന്ത്രിക്കുക."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ജെസ്‌റ്ററുകൾ നിർവഹിക്കുക"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ടാപ്പുചെയ്യാനോ സ്വൈപ്പുചെയ്യാനോ പിഞ്ചുചെയ്യാനോ മറ്റ് ജെസ്‌റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ഫിംഗർപ്രിന്റ് ജെസ്‌റ്ററുകൾ"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ഉപകരണത്തിന്റെ ഫിംഗർപ്രിന്റ് സെൻസറിൽ ചെയ്‌ത ജെസ്‌റ്ററുകൾ ക്യാപ്‌ചർ ചെയ്യാനാകും."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"സ്റ്റാറ്റസ് ബാർ പ്രവർത്തനരഹിതമാക്കുക അല്ലെങ്കിൽ പരിഷ്‌ക്കരിക്കുക"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"നില ബാർ പ്രവർത്തരഹിതമാക്കുന്നതിന് അല്ലെങ്കിൽ സിസ്‌റ്റം ഐക്കണുകൾ ചേർക്കുന്നതിനും നീക്കംചെയ്യുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"സ്റ്റാറ്റസ് ബാർ ആയിരിക്കുക"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ഡീബഗ്ഗിംഗ് പ്രവർത്തനരഹിതമാക്കാൻ ടാപ്പുചെയ്യുക."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ബഗ് റിപ്പോർട്ട് എടുക്കുന്നു…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നു…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"വാർത്തകളും മാസികകളും"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"മാപ്സും നാവിഗേഷനും"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ഉല്‍‌പ്പാദനക്ഷമത"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ഉപകരണ സ്റ്റോറേജ്"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 2af81c4..0f7d43a 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Дэлгэцийн томруулах түвшин болон байршлыг хянах."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Зангах"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Товших, шудрах, жижигрүүлэх болон бусад зангааг хийх боломжтой."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Хурууны хээний зангаа"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Төхөөрөмжийн хурууны хээ мэдрэгчид зангасан зангааг танина."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"статус самбарыг идэвхгүй болгох болон өөрчлөх"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Апп нь статус самбарыг идэвхгүй болгох эсвэл систем дүрсийг нэмэх, хасах боломжтой."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"статусын хэсэг болох"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Бусад сонголтыг харахын тулд товшино уу."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB-н алдаа засварлахыг идэвхгүй болгохын тулд товшино уу."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB дебаг хийхийг идэвхгүй болгох бол сонгоно уу."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Алдааны тайланг авч байна..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Алдааны тайланг хуваалцах уу?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Алдааны тайланг хуваалцаж байна..."</string>
@@ -1687,4 +1690,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Мэдээ &amp; сэтгүүл"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Газрын зураг &amp; зүг чиг"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Бүтээмж"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Төхөөрөмжийн сан"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 1be89c2..69cf831 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शनाचा झूम स्तर आणि स्थिती निर्धारण नियंत्रित करा."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"जेश्चर करा"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"टॅप, स्वाइप, पिंच आणि इतर जेश्चर करू शकते."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"फिंगरप्रिंट जेश्चर"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"डिव्‍हाइसच्‍या फिंगरप्रिंट सेंसरवर केलेले जेश्चर कॅप्‍चर करू शकते."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"स्टेटस बार अक्षम करा किंवा सुधारित करा"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"स्टेटस बार अक्षम करण्यासाठी किंवा सिस्टीम चिन्हे जोडण्यासाठी आणि काढण्यासाठी अॅप ला अनुमती देते."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"स्टेटस बार होऊ द्या"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"अधिक पर्यायांसाठी टॅप करा."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग करणे कनेक्‍ट केले"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डीबग करणे अक्षम करण्यासाठी टॅप करा."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"दोष अहवाल घेत आहे..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग अहवाल सामायिक करायचा?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"दोष अहवाल सामायिक करीत आहे..."</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"बातम्‍या आणि मासिके"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"नकाशे आणि नेव्हिगेशन"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"उत्पादनक्षमता"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"डिव्‍हाइस संचय"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index ad1f4cb..ad053b9 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kawal tahap zum dan kedudukan paparan."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Lakukan gerak isyarat"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Boleh ketik, leret, cubit dan laksanakan gerak isyarat lain."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gerak isyarat cap jari"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Boleh menangkap gerak isyarat yang dilakukan pada penderia cap jari peranti."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"lumpuhkan atau ubah suai bar status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Membenarkan apl melumpuhkan bar status atau menambah dan mengalih keluar ikon sistem."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"jadi bar status"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Ketik untuk mendapatkan lagi pilihan."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Penyahpepijatan USB disambungkan"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Ketik untuk melumpuhkan penyahpepijatan USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk melumpuhkan penyahpepijatan USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan pepijat…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kongsi laporan pepijat?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Berkongsi laporan pepijat…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Berita &amp; Majalah"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Peta &amp; Navigasi"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktiviti"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Storan peranti"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 129eefd..4454c2b5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"မျက်နှာပြင် ဇူးမ်အရွယ်နှင့် နေရာချထားခြင်းကို ထိန်းချုပ်ပါ။"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"လက်ဟန်များ အသုံးပြုပါ"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"တို့ခြင်း၊ ပွတ်ဆွဲခြင်း၊ နှင့် အခြား လက်ဟန်များကို အသုံးပြုနိုင်ပါသည်။"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"လက်ဗွေရာများ"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ကိရိယာ၏ လက်ဗွေအာရုံခံကိရိယာတွင် နှိပ်ထားသည်များကို မှတ်သားထားနိုင်သည်။"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"အခြေအနေပြဘားအား အလုပ်မလုပ်ခိုင်းရန်သို့မဟုတ် မွမ်းမံရန်"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"အက်ပ်အား အခြေအနေပြ ဘားကို ပိတ်ခွင့် သို့မဟတ် စနစ် အိုင်ကွန်များကို ထည့်ခြင်း ဖယ်ရှားခြင်း ပြုလုပ်ခွင့် ပြုသည်။"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"အခြေအနေပြ ဘားဖြစ်ပါစေ"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"နောက်ထပ်ရွေးချယ်စရာများအတွက် တို့ပါ။"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB အမှားစစ်ခြင်းအား ချိတ်ဆက်ထားသည်"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ဆက်သွယ်ရေးစနစ်ကို ပိတ်ရန် တို့ပါ။"</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ချွတ်ယွင်းချက် အစီရင်ခံစာပြုစုနေသည်..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို မျှဝေမလား။"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ချွတ်ယွင်းမှုအစီရင်ခံစာ မျှဝေနေသည်…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"သတင်းနှင့် မဂ္ဂဇင်းများ"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"မြေပုံနှင့် ခရီးလမ်းညွှန်ချက်"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ထုတ်လုပ်နိုင်မှု"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"စက်ပစ္စည်း သိုလှောင်ခန်း"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 9ef1bb3..d23441f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér zoomenivået og plasseringen for skjermen."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gjøre bevegelser"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, sveipe, klype og gjøre andre bevegelser."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Bevegelser på fingeravtrykkssensor"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan fange inn bevegelser som utføres på enhetens fingeravtrykkssensor."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"deaktivere eller endre statusfeltet"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Lar appen deaktivere statusfeltet eller legge til og fjerne systemikoner."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vise appen i statusfeltet"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Trykk for å få flere alternativ."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-feilsøking tilkoblet"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Trykk for å slå av feilsøking via USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Velg for å deaktivere USB-debugging."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kjører feilrapport …"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele feilrapporten?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler feilrapporten …"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Nyheter og tidsskrifter"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kart og navigering"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Lagring på enheten"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 6ebbc93..d513ff3 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शनको जुम स्तर र स्थिति नियन्त्रण गर्नुहोस्।"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"इसाराहरू सम्बन्धी कार्य गर्नुहोस्"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ट्याप, स्वाइप गर्न, थिच्न र अन्य इसाराहरू सम्बन्धी कार्य गर्न सक्छ"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"फिंगरप्रिन्टका इसाराहरू"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"यन्त्रहरूक‍ो फिंगरप्रिन्ट सेन्सरमा गरिएका इसाराहरू कैद गर्न सक्छ।"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"स्थिति पट्टिलाई अक्षम वा संशोधित गर्नुहोस्"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"स्थिति पट्टि असक्षम पार्न वा प्रणाली आइकनहरू थप्न र हटाउन अनुप्रयोगलाई अनुमति दिन्छ।"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"वस्तुस्थिति पट्टी हुन दिनुहोस्"</string>
@@ -1152,6 +1154,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"थप विकल्पहरूका लागि ट्याप गर्नुहोस्।"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने जडित छ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डिबगिङलाई असक्षम गर्न ट्याप गर्नुहोस्।"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डिबगिङ असक्षम पार्न चयन गर्नुहोस्।"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट लिँदै..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्टलाई साझेदारी गर्ने हो?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्टलाई साझेदारी गर्दै ..."</string>
@@ -1695,4 +1698,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"समाचार तथा पत्रिकाहरू"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"नक्सा तथा नेभिगेसन"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"उत्पादकत्व"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"यन्त्रको भण्डारण"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 8ece49e..f3e0274 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Bedien het zoomniveau en de positionering van het scherm."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gebaren uitvoeren"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tikken, vegen, samenknijpen en andere gebaren uitvoeren."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Vingerafdrukgebaren"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan gebaren registreren die op de vingerafdruksensor van het apparaat worden getekend."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Hiermee kan de app de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"de statusbalk zijn"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tik voor meer opties."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tik om USB-foutopsporing uit te schakelen."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecteer deze optie om USB-foutopsporing uit te schakelen."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Bugrapport genereren…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bugrapport delen?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bugrapport delen…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Nieuws en tijdschriften"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Maps en navigatie"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productiviteit"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Apparaatopslag"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 8438fb9..788efb8 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ਡਿਸਪਲੇ ਦੇ ਜ਼ੂਮ ਪੱਧਰ ਅਤੇ ਸਥਿਤੀ ਨੂੰ ਨਿਯੰਤ੍ਰਿਤ ਕਰੋ।"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ਸੰਕੇਤ ਕਰਦੀ ਹੈ"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ਟੈਪ ਕਰ ਸਕਦੀ ਹੈ, ਸਵਾਈਪ ਕਰ ਸਕਦੀ ਹੈ, ਪਿੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਅਤੇ ਹੋਰ ਸੰਕੇਤ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੰਕੇਤ"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"ਡੀਵਾਈਸਾਂ ਦੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ \'ਤੇ ਕੀਤੇ ਗਏ ਸੰਕੇਤਾਂ ਨੂੰ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"ਸਥਿਤੀ ਬਾਰ ਅਸਮਰੱਥ ਬਣਾਓ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"ਐਪ ਨੂੰ ਸਥਿਤੀ ਬਾਰ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਉਣ ਜਾਂ ਸਿਸਟਮ ਆਈਕਨਾਂ ਨੂੰ ਜੋੜਨ ਅਤੇ ਹਟਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ਸਥਿਤੀ ਪੱਟੀ ਬਣਨ ਦਿਓ"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ਡੀਬੱਗਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ਬੱਗ ਰਿਪਰੋਟ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ਕੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"ਖਬਰਾਂ ਅਤੇ ਰਸਾਲੇ"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"ਨਕਸ਼ੇ ਅਤੇ ਆਵਾਗੌਣ"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ਉਤਪਾਦਕਤਾ"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ਡੀਵਾਈਸ ਸਟੋਰੇਜ"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 125f3f2..3814f80 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Regulowanie poziomu i obszaru powiększenia ekranu."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obsługa gestów"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Obsługuje kliknięcia, przesunięcia, ściągnięcia palców i inne gesty."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesty związane z odciskiem palca"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Może przechwytywać gesty wykonywane na czytniku linii papilarnych w urządzeniu."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Pozwala aplikacji na wyłączanie paska stanu oraz dodawanie i usuwanie ikon systemowych."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"działanie jako pasek stanu"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Kliknij, by wyświetlić więcej opcji."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Kliknij, by wyłączyć debugowanie USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Wybierz, aby wyłączyć debugowanie USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zgłaszam błąd…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Udostępnić raport o błędzie?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Udostępniam raport o błędzie…"</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Wiadomości i czasopisma"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapy i nawigacja"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktywność"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Pamięć urządzenia"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index c6d217a..a7a763f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de impressão digital"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode captar gestos realizados no sensor de impressão digital do dispositivo."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Toque para ver mais opções."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Notícias e revistas"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegação"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Armazenamento do dispositivo"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index eabc2f4..b87fe9e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nível de zoom e o posicionamento do ecrã."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"É possível tocar, deslizar rapidamente, juntar os dedos e realizar outros gestos"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de impressão digital"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode capturar gestos realizados no sensor de impressões digitais do dispositivo."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite à aplicação desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ser apresentada na barra de estado"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Toque para obter mais opções."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccione para desativar depuração USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"A criar relatório de erro…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Pretende partilhar o relatório de erro?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"A partilhar relatório de erro…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Notícias e revistas"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegação"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Armazenamento do dispositivo"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c6d217a..a7a763f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de impressão digital"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode captar gestos realizados no sensor de impressão digital do dispositivo."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Toque para ver mais opções."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Notícias e revistas"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapas e navegação"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produtividade"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Armazenamento do dispositivo"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5e7df4b..b407ae0 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -281,6 +281,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlați nivelul de zoom și poziționarea afișajului."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Folosiți gesturi"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Se poate atinge, glisa, ciupi și se pot folosi alte gesturi."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesturi ce implică amprente"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Poate reda gesturile făcute pe senzorul de amprentă al dispozitivelor."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"dezactivare sau modificare bare de stare"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite aplicației să dezactiveze bara de stare sau să adauge și să elimine pictograme de sistem."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"să fie bara de stare"</string>
@@ -1166,6 +1168,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Atingeți pentru mai multe opțiuni."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Atingeți ca să dezactivați remedierea erorilor prin USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selectați pentru a dezactiva depanarea USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Se creează un raport de eroare…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Trimiteți raportul de eroare?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Se trimite raportul de eroare…"</string>
@@ -1720,4 +1723,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Știri și reviste"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Hărți și navigare"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivitate"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Stocare pe dispozitiv"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5aabe4d..2e2bd0b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управлять позиционированием и размером изображения на экране."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Жесты"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Может выполнять жесты нажатия, пролистывания, масштабирования и т. д."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жесты для отпечатков пальцев"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Сохраняет жесты, выполненные на сканере отпечатков пальцев."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Отключение/изменение строки состояния"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Приложение сможет отключать строку состояния, а также добавлять и удалять системные значки."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Замена строки состояния"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Нажмите, чтобы показать дополнительные параметры."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Нажмите, чтобы отключить отладку по USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Нажмите, чтобы отключить отладку USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Подготовка отчета об ошибке"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Разрешить доступ к информации об ошибке?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Отправка отчета об ошибке"</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Новости и журналы"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Карты и навигация"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Работа"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Хранилище устройства"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index d776aaa..7440888 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"සංදර්ශනයේ විශාලන මට්ටම සහ පිහිටීම පාලනය කරන්න."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"අභින සිදු කරන්න"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"තට්ටු කිරීමට, ස්වයිප් කිරීමට, පින්ච් කිරීමට, සහ වෙනත් අභින සිදු කිරීමට හැකිය."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ඇඟිලි සලකුණු ඉංගිත"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"උපාංග ඇඟිලි සලකුණු සංවේදකය මත සිදු කරන ඉංගිත ග්‍රහණය කළ හැකිය."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"තත්ව තීරුව අබල කරන්න හෝ වෙනස් කරන්න"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"තත්ව තීරුව අක්‍රිය කිරීමට හෝ පද්ධති නිරූපක එකතු හෝ ඉවත් කිරීමට යෙදුමට අවසර දේ."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"තත්ත්ව තීරුව බවට පත්වීම"</string>
@@ -1148,6 +1150,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"තවත් විකල්ප සඳහා තට්ටු කරන්න."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB නිදොස්කරණය සම්බන්ධිතයි"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB නිදොස්කරණය අබල කිරීමට තට්ටු කරන්න."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB නිදොස්කරණය අබල කිරීමට තෝරන්න."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"දෝෂ වාර්තාවක් ගනිමින්…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"දෝෂ වාර්තාව බෙදා ගන්නද?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"දෝෂ වාර්තාවක් බෙදා ගනිමින්..."</string>
@@ -1691,4 +1694,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"පුවත් සහ සඟරා"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"සිතියම් සහ සංචලනය"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ඵලදායිතාව"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"උපාංග ගබඩාව"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c7b094a..47716da 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ovládajte úroveň priblíženia/oddialenia obrazovky a umiestnenie"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gestá"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Je možné použiť klepnutie, prejdenie, stiahnutie prstami a ďalšie gestá."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestá odtlačkov prstov"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dokáže zaznamenať gestá vykonané na senzore odtlačkov prstov."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"zakázanie alebo zmeny stavového riadka"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikácii vypnúť stavový riadok alebo pridať a odstrániť systémové ikony."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vydávanie sa za stavový riadok"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Klepnutím zobrazíte ďalšie možnosti."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Klepnutím zakážete ladenie cez USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Výberom zakážete ladenie USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Preberá sa hlásenie chyby…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chcete zdieľať hlásenie chyby?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Zdieľa sa hlásenie chyby…"</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Noviny a časopisy"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mapy a navigácia"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivita"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Úložisko zariadenia"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ab8264c..13102b5 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Nadziranje stopnje povečave in položaja prikaza."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvajanje potez"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mogoče je izvajanje dotikov, vlečenja, primikanja in razmikanja prstov ter drugih potez."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Poteze po tipalu prstnih odtisov"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Prepoznava poteze, narejene po tipalu prstnih odtisov naprave."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"onemogočanje ali spreminjanje vrstice stanja"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikacijam omogoča onemogočenje vrstice stanja ali dodajanje in odstranjevanje ikon sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"postane vrstica stanja"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Dotaknite se za več možnosti."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje napak prek USB je povezano"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dotaknite se za izklop odpravljanja napak prek USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izberite, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zajemanje poročila o napakah …"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite poslati poročilo o napakah?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Pošiljanje poročila o napakah …"</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Novice in revije"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Zemljevidi in navigacija"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Storilnost"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Shramba naprave"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index fc9384c..fd76f7d 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollo nivelin dhe pozicionimin e zmadhimit të ekranit."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kryen gjeste"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mund të trokasë, rrëshqasë, bashkojë gishtat dhe kryejë gjeste të tjera."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gjestet e gjurmës së gishtit"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Mund të kapë gjestet e kryera në sensorin e gjurmës së gishtit të pajisjeve."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"çaktivizo ose modifiko shiritin e statusit"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Lejon aplikacionin të çaktivizojë shiritin e statusit dhe të heqë ikonat e sistemit."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"të bëhet shiriti i statusit"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Trokit për më shumë opsione."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Korrigjuesi i USB-së i lidhur"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Trokit për të çaktivizuar korrigjimin e gabimeve të USB-së."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Po merret raporti i defekteve në kod…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Të ndahet raporti i defektit në kod?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Po ndan raportin e defekteve në kod..."</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Lajme dhe revista"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Harta dhe navigim"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Hapësira ruajtëse e pajisjes"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 93253c2..54b0fae 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -281,6 +281,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управља нивоом зумирања приказа и одређивањем положаја."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Обављање покрета"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Може да додирује, листа, скупља приказ и обавља друге покрете."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Покрети за отисак прста"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Може да региструје покрете на сензору за отисак прста на уређају."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"онемогућавање или измена статусне траке"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Дозвољава апликацији да онемогући статусну траку или да додаје и уклања системске иконе."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"функционисање као статусна трака"</string>
@@ -1166,6 +1168,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Додирните за још опција."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изаберите да бисте онемогућили отклањања грешака са USB-а."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Извештај о грешци се генерише…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Желите ли да поделите извештај о грешци?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Дели се извештај о грешци…"</string>
@@ -1720,4 +1723,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Новости и часописи"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Мапе и навигација"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Продуктивност"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Меморијски простор уређаја"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 88089b9..e010b96 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Styr skärmens zoomnivå och positionering."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Göra rörelser"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trycka, svepa, nypa och göra andra rörelser."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingeravtrycksrörelser"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Kan registrera rörelser som utförs med hjälp av enhetens fingeravtryckssensor."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"inaktivera eller ändra statusfält"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Tillåter att appen inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"visas i statusfältet"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Tryck för fler alternativ."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck om du vill inaktivera USB-felsökning."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj att inaktivera USB-felsökning."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Felrapporten överförs …"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Felrapporten delas …"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Nyheter och tidskrifter"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Kartor och navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Produktivitet"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Enhetens lagringsutrymme"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index db6f8cf..c363a22 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -276,6 +276,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Dhibiti kiwango cha kukuza na nafasi cha onyesho."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Tekeleza ishara"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Unaweza kugonga, kutelezesha kidole, kubana na kutekeleza ishara zingine."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Ishara za alama ya kidole"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Inaweza kurekodi ishara zinazotekelezwa kwenye kitambua alama ya kidole."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"zima au rekebisha mwambaa hali"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Inaruhusu programu kulemaza upau wa hali au kuongeza na kutoa ikoni za mfumo."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"kuwa sehemu ya arifa"</string>
@@ -1144,6 +1146,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Gonga ili upate chaguo zaidi."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji wa USB umeunganishwa"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Gonga ili uzime utatuaji wa USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chagua ili kulemaza utatuaji USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Inatayarisha ripoti ya hitilafu…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Ungependa kushiriki ripoti ya hitilafu?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Inashiriki ripoti ya hitilafu…"</string>
@@ -1687,4 +1690,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Habari na Magazeti"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Ramani na Maelekezo"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Uzalishaji"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Hifadhi ya kifaa"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e259a39..8a70c4e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"திரையின் ஜூம் அளவையும் நிலையையும் கட்டுப்படுத்தலாம்."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"சைகைகளைச் செயல்படுத்துதல்"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"தட்டலாம், ஸ்வைப் செய்யலாம், பின்ச் செய்யலாம் மற்றும் பிற சைகைகளைச் செயல்படுத்தலாம்."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"கைரேகை சைகைகள்"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"சாதனத்தின் கைரேகை உணர்வி மேல் செய்யப்படும் சைகைகளைப் படமெடுக்க முடியும்."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"நிலைப் பட்டியை முடக்குதல் அல்லது மாற்றுதல்"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"நிலைப் பட்டியை முடக்க அல்லது முறைமையில் ஐகான்களைச் சேர்க்க மற்றும் அகற்ற பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"நிலைப் பட்டியில் இருக்கும்"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"மேலும் விருப்பங்களுக்கு, தட்டவும்."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB பிழை திருத்தத்தை முடக்க, தட்டவும்."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"பிழை அறிக்கையை எடுக்கிறது…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"பிழை அறிக்கையைப் பகிரவா?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"பிழை அறிக்கையைப் பகிர்கிறது…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"செய்திகளும் பத்திரிகைகளும்"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"வரைபடங்களும் வழிசெலுத்தலும்"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"உற்பத்தித்திறன்"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"சாதனச் சேமிப்பகம்"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index dc5653c..4d22092 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"డిస్‌ప్లే జూమ్ స్థాయి మరియు స్థానాన్ని నియంత్రిస్తుంది."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"సంజ్ఞలను చేయడం"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"నొక్కగలరు, స్వైప్ చేయగలరు, స్క్రీన్‌పై రెండు వేళ్లను ఉంచి ఆ వేళ్లను దగ్గరకు లేదా దూరానికి లాగగలరు మరియు ఇతర సంజ్ఞలను చేయగలరు."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"వేలిముద్ర సంజ్ఞలు"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"పరికరాల వేలిముద్ర సెన్సార్‌లో నిర్వహించిన సంజ్ఞలను క్యాప్చర్ చేయవచ్చు."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"స్థితి బార్‌ను నిలిపివేయడం లేదా సవరించడం"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"స్థితి బార్‌ను నిలిపివేయడానికి లేదా సిస్టమ్ చిహ్నాలను జోడించడానికి మరియు తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"స్థితి పట్టీగా ఉండటం"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"మరిన్ని ఎంపికల కోసం నొక్కండి."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB డీబగ్గింగ్‌ను నిలిపివేయడానికి నొక్కండి."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"బగ్ నివేదికను తీస్తోంది…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"వార్తలు &amp; వార్తాపత్రికలు"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"మ్యాప్స్ &amp; నావిగేషన్"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ఉత్పాదకత"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"పరికర నిల్వ"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ae84073..38dfd84 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ควบคุมระดับการซูมและการวางตำแหน่งของการแสดงผล"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ทำท่าทางสัมผัส"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"สามารถแตะ เลื่อน บีบ และทำท่าทางสัมผัสอื่นๆ"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ท่าทางสัมผัสลายนิ้วมือ"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"สามารถจับท่าทางสัมผัสที่เกิดขึ้นบนเซ็นเซอร์ลายนิ้วมือของอุปกรณ์"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"ปิดการใช้งานหรือแก้ไขแถบสถานะ"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"อนุญาตให้แอปพลิเคชันปิดใช้งานแถบสถานะหรือเพิ่มและนำไอคอนระบบออก"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"เป็นแถบสถานะ"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"แตะเพื่อปิดใช้การแก้ไขข้อบกพร่องของ USB"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"เลือกเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"กำลังสร้างรายงานข้อบกพร่อง…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"แชร์รายงานข้อบกพร่องไหม"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"กำลังแชร์รายงานข้อบกพร่อง…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"ข่าวสารและนิตยสาร"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"แผนที่และการนำทาง"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"ประสิทธิภาพการทำงาน"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"พื้นที่เก็บข้อมูลของอุปกรณ์"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 3ca68da..06c6aa7 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolin ang antas ng pag-zoom at pagpoposisyon ng display."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Magsagawa ng mga galaw"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"May kakayahang mag-tap, mag-swipe, mag-pinch at magsagawa ng iba pang mga galaw."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Mga galaw gamit ang fingerprint"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Makukunan ang mga galaw na ginawa sa sensor para sa fingerprint ng mga device."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"i-disable o baguhin ang status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Pinapayagan ang app na i-disable ang status bar o magdagdag at mag-alis ng mga icon ng system."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"maging status bar"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"I-tap para sa higit pang mga opsyon."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pag-debug ng USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Piliin upang i-disable ang debugging ng USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kinukuha ang ulat ng bug…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Balita at Mga Magazine"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Mga Mapa at Navigation"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Productivity"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Storage ng device"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 70183a1..c6dd402 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranın yakınlaştırma seviyesini ve konumunu kontrol edin."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Haraketleri yapma"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Hafifçe dokunabilir, hızlıca kaydırabilir, sıkıştırabilir ve diğer hareketleri yapabilirsiniz."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Parmak izi hareketleri"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Cihazların parmak izi sensörlerinde gerçekleştirilen hareketleri yakalayabilir."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Uygulamaya, durum çubuğunu devre dışı bırakma ve sistem simgelerini ekleyip kaldırma izni verir."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"durum çubuğunda olma"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Diğer seçenekler için dokunun."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB hata ayıklamasını devre dışı bırakmak için tıklayın."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hata raporu alınıyor…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Hata raporu paylaşılsın mı?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hata raporu paylaşılıyor..."</string>
@@ -1232,7 +1235,7 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirim dinleyici"</string>
-    <string name="vr_listener_binding_label" msgid="4316591939343607306">"Sanal Gerçeklik dinleyici"</string>
+    <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR dinleyici"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Durum sağlayıcı"</string>
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Bildirim sıralama hizmeti"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Haberler ve Dergiler"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Haritalar ve Navigasyon"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Verimlilik"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Cihazdaki depolama alanı"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 3fd1f23..6b5070a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -284,6 +284,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Контролювати масштаб і розташування екрана."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Виконання жестів"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можна торкатися, проводити пальцем, стискати пальці та виконувати інші жести."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жести на сканері відбитків пальців"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Фіксуються жести на сканері відбитків пальців."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"вимикати чи змін. рядок стану"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Дозволяє програмі вимикати рядок стану чи додавати та видаляти піктограми системи."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"відображатися як рядок стану"</string>
@@ -1186,6 +1188,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Торкніться, щоб переглянути більше опцій."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB завершено"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Торкніться, щоб вимкнути налагодження USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Вибер., щоб вимкн. налагодж. USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Створюється повідомлення про помилку…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Надіслати звіт про помилку?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Надсилається звіт про помилку…"</string>
@@ -1751,4 +1754,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Новини та журнали"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Карти й навігація"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Продуктивність"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Пам’ять пристрою"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 86515b3..9f77dbb 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ڈسپلے کے زوم کی سطح اور پوزیشن کو کنٹرول کریں۔"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"اشارے انجام دیں"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"تھپتھپانا، سوائپ کرنا، چٹکی بھرنا اور دیگر اشارے انجام دے سکتی ہے"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"فنگرپرنٹ کے اشارے"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"آلات کے فنگر پرنٹ سینسر پر کیے گئے اشاروں کو کیپچر کر سکتا ہے۔"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"اسٹیٹس بار کو غیر فعال یا اس میں ترمیم کریں"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"ایپ کو اسٹیٹس بار غیر فعال کرنے یا سسٹم آئیکنز شامل کرنے اور ہٹانے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"بطور اسٹیٹس بار کام لیں"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"مزید اختیارات کیلئے تھپتھپائیں۔"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏USB ڈیبگ کرنا مربوط ہو گیا"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏USB ڈیبگنگ کو غیر فعال کرنے کیلئے تھپتھپائیں۔"</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"بگ رپورٹ لی جا رہی ہے…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"بگ رپورٹ کا اشتراک کریں؟"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"بگ رپورٹ کا اشتراک ہو رہا ہے…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"خبریں اور میگزین"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"نقشے اور نیویگیشن"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"پروڈکٹیوٹی"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"آلہ کی اسٹوریج"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 5f978c6..6f07869 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranni kattalashtirish darajasi va joylashuvini boshqaradi."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Imo-ishoralar bilan boshqarish"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Bosish, surish; jipslashtirish va boshqa imo-ishoralarni amalga oshirish mumkin."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Barmoq izi ishoralari"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Barmoq izi skanerlarida kiritilgan ishoralarni taniy oladi."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"holat panelini o‘zgartirish yoki o‘chirish"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ilova holat panelini o‘chirib qo‘yishi hamda tizim ikonkalarini qo‘shishi yoki olib tashlashi mumkin."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"holat qatorida ko‘rinishi"</string>
@@ -1146,6 +1148,8 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Boshqa parametrlarini ko‘rish uchun bosing."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"O‘chirib qo‘yish uchun bu yerga bosing."</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Xatoliklar hisoboti olinmoqda…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Xatoliklar hisoboti yuborilsinmi?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Xatoliklar hisoboti yuborilmoqda…"</string>
@@ -1689,4 +1693,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Yangiliklar va jurnallar"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Xaritalar va navigatsiya"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Ish va unumdorlik"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Qurilma xotirasi"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e2c6e32..f2d9c8f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kiểm soát vị trí và mức thu phóng của màn hình."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Thực hiện cử chỉ"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Có thể nhấn, vuốt, chụm và thực hiện các cử chỉ khác."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Cử chỉ vân tay"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Có thể ghi lại các cử chỉ được thực hiện trên cảm biến vân tay của thiết bị."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"vô hiệu hóa hoặc sửa đổi thanh trạng thái"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Cho phép ứng dụng vô hiệu hóa thanh trạng thái hoặc thêm và xóa biểu tượng hệ thống."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"trở thành thanh trạng thái"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Nhấn để biết thêm tùy chọn."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Nhấn để vô hiệu hóa gỡ lỗi USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chọn để vô hiệu hóa gỡ lỗi USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Đang thu thập báo cáo lỗi…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chia sẻ báo cáo lỗi?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Đang chia sẻ báo cáo lỗi…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Tin tức và tạp chí"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Bản đồ và dẫn đường"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Sản xuất"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Bộ nhớ của thiết bị"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 12f419b..96eba47 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控制显示内容的缩放级别和位置。"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"执行手势"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可执行点按、滑动、双指张合等手势。"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指纹手势"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"可以捕获在设备指纹传感器上执行的手势。"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"停用或修改状态栏"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"允许应用停用状态栏或者增删系统图标。"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"用作状态栏"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"点按即可查看更多选项。"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到USB调试"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"点按即可停用 USB 调试功能。"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"选择停用USB调试。"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在生成错误报告…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享错误报告吗?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享错误报告…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"新闻和杂志"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"地图和导航"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"办公"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"设备存储空间"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 9996617..234d45b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控制顯示屏的縮放程度和位置。"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"執行手勢"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可以輕按、快速滑動和兩指縮放,並執行其他手勢。"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指紋手勢"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"可擷取裝置指紋感應器上執行的手勢。"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"停用或修改狀態列"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"成為狀態列"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"輕按即可查看更多選項。"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"輕按即可停用 USB 偵錯功能。"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取即可停用 USB 偵錯。"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在取得錯誤報告…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"新聞和雜誌"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"地圖和導航"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"生產力應用程式"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"裝置儲存空間"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 04c5a8e..0f0f176 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"控管顯示畫面的縮放等級和位置。"</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"使用手勢"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"可使用輕觸、滑動和雙指撥動等手勢。"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"指紋手勢"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"可以擷取在裝置指紋感應器上執行的手勢。"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"停用或變更狀態列"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"以狀態列顯示"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"輕觸即可查看更多選項。"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"輕觸即可停用 USB 偵錯。"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取以停用 USB 偵錯。"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在接收錯誤報告…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"新聞和雜誌"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"地圖和導航"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"生產應用"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"裝置儲存空間"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 095341a..938b332 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -278,6 +278,8 @@
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Lawula ileveli yokusondeza yesibonisi nendawo."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Yenza ukuthinta"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Ingathepha, iswayiphe, incinze, futhi yenze okunye ukuthintwa."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Ukuthinta kwezigxivizo zeminwe"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Ingathatha ukuthinta okwenziwe kunzwa yezigxivizo zeminwe zamadivayisi."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"khubaza noma guqula ibha yomumo"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela uhlelo lokusebenza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"yiba yibha yesimo"</string>
@@ -1146,6 +1148,7 @@
     <string name="usb_notification_message" msgid="3370903770828407960">"Thepha ngezinketho eziningi."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Thepha ukuze ukhubaze ukususa isiphazamisi se-USB."</string>
+    <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Khetha ukuvimbela ukulungisa iphutha le-USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Ithatha umbiko wesiphazamisi..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Yabelana ngombiko wesiphazamisi?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Yabelana ngombiko wesiphazamisi..."</string>
@@ -1689,4 +1692,7 @@
     <string name="app_category_news" msgid="7496506240743986873">"Izindaba nomagazini"</string>
     <string name="app_category_maps" msgid="5878491404538024367">"Amamephu nokuzula"</string>
     <string name="app_category_productivity" msgid="3742083261781538852">"Ukukhiqiza"</string>
+    <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Isitoreji sedivayisi"</string>
+    <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c548219..aeba589 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3392,6 +3392,8 @@
             <flag name="flagRetrieveInteractiveWindows" value="0x00000040" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_ENABLE_ACCESSIBILITY_VOLUME} -->
             <flag name="flagEnableAccessibilityVolume" value="0x00000080" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} -->
+            <flag name="flagRequestAccessibilityButton" value="0x00000100" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_CAPTURE_FINGERPRINT_GESTURES} -->
             <flag name="flagCaptureFingerprintGestures" value="0x00000200" />
         </attr>
@@ -3429,18 +3431,9 @@
         <attr name="canRequestFilterKeyEvents" format="boolean" />
         <!-- Attribute whether the accessibility service wants to be able to control
              display magnification.
-             <p>
-             Required to allow setting the {@link android.accessibilityservice
-             #AccessibilityServiceInfo#FLAG_CAN_CONTROL_MAGNIFICATION} flag.
-             </p>
          -->
         <attr name="canControlMagnification" format="boolean" />
-        <!-- Attribute whether the accessibility service wants to be able to perform gestures.
-             <p>
-             Required to allow setting the {@link android.accessibilityservice
-             #AccessibilityServiceInfo#FLAG_CAN_PERFORM_GESTURES} flag.
-             </p>
-         -->
+        <!-- Attribute whether the accessibility service wants to be able to perform gestures. -->
         <attr name="canPerformGestures" format="boolean" />
         <!-- Attribute whether the accessibility service wants to be able to capture gestures from
              the fingerprint sensor.
@@ -6982,10 +6975,32 @@
              with alphabetic keys. -->
         <attr name="alphabeticShortcut" format="string" />
 
+        <!-- The alphabetic modifier key. This is the modifier when using a keyboard
+             with alphabetic keys. The values should be kept in sync with KeyEvent -->
+        <attr name="alphabeticModifiers">
+            <flag name="META" value="0x10000" />
+            <flag name="CTRL" value="0x1000" />
+            <flag name="ALT" value="0x02" />
+            <flag name="SHIFT" value="0x1" />
+            <flag name="SYM" value="0x4" />
+            <flag name="FUNCTION" value="0x8" />
+        </attr>
+
         <!-- The numeric shortcut key.  This is the shortcut when using a numeric (e.g., 12-key)
              keyboard. -->
         <attr name="numericShortcut" format="string" />
 
+        <!-- The numeric modifier key. This is the modifier when using a numeric (e.g., 12-key)
+             keyboard. The values should be kept in sync with KeyEvent -->
+        <attr name="numericModifiers">
+            <flag name="META" value="0x10000" />
+            <flag name="CTRL" value="0x1000" />
+            <flag name="ALT" value="0x02" />
+            <flag name="SHIFT" value="0x1" />
+            <flag name="SYM" value="0x4" />
+            <flag name="FUNCTION" value="0x8" />
+        </attr>
+
         <!-- Whether the item is capable of displaying a check mark. -->
         <attr name="checkable" format="boolean" />
 
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6d0fdb6..76f4a76 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -885,6 +885,12 @@
          will run against. -->
     <attr name="targetPackage" format="string" />
 
+    <!-- The name of an application's processes that an Instrumentation object
+         will run against.  If not specified, only runs in the main process of the targetPackage.
+         Can either be a comma-separated list of process names or '*' for any process that
+         launches to run targetPackage code. -->
+    <attr name="targetProcess" format="string" />
+
     <!-- Flag indicating that an Instrumentation class wants to take care
          of starting/stopping profiling itself, rather than relying on
          the default behavior of profiling the complete time it is running.
@@ -2050,9 +2056,6 @@
              in a task/stack that isn't focusable. This flag allows them to be focusable.-->
         <attr name="alwaysFocusable" format="boolean" />
         <attr name="enableVrMode" />
-        <!-- @hide This activity is a launcher which should always show up on the top of others.
-             This attribute is ignored if the activity isn't a launcher. -->
-        <attr name="onTopLauncher" format="boolean" />
         <attr name="rotationAnimation" />
         <attr name="visibleToInstantApps" />
         <!-- The code for this component is located in the given split. -->
@@ -2297,6 +2300,7 @@
             is a period then it is appended to your package name. -->
         <attr name="name" />
         <attr name="targetPackage" />
+        <attr name="targetProcess" />
         <attr name="label" />
         <attr name="icon" />
         <attr name="roundIcon" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 927988f..640e74d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -461,12 +461,12 @@
     <dimen name="floating_toolbar_height">48dp</dimen>
     <dimen name="floating_toolbar_menu_image_button_width">56dp</dimen>
     <dimen name="floating_toolbar_menu_image_button_vertical_padding">12dp</dimen>
-    <dimen name="floating_toolbar_menu_button_side_padding">16dp</dimen>
+    <dimen name="floating_toolbar_menu_button_side_padding">11dp</dimen>
     <dimen name="floating_toolbar_overflow_image_button_width">60dp</dimen>
     <dimen name="floating_toolbar_overflow_side_padding">18dp</dimen>
     <dimen name="floating_toolbar_text_size">14sp</dimen>
     <dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen>
-    <dimen name="floating_toolbar_preferred_width">328dp</dimen>
+    <dimen name="floating_toolbar_preferred_width">400dp</dimen>
     <dimen name="floating_toolbar_minimum_overflow_height">96dp</dimen>
     <dimen name="floating_toolbar_maximum_overflow_height">192dp</dimen>
     <dimen name="floating_toolbar_horizontal_margin">16dp</dimen>
@@ -475,9 +475,6 @@
 
     <dimen name="chooser_grid_padding">0dp</dimen>
 
-    <item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
-
     <item type="dimen" name="aerr_padding_list_top">15dp</item>
     <item type="dimen" name="aerr_padding_list_bottom">8dp</item>
 
@@ -520,6 +517,7 @@
     <dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen>
 
     <!-- The elevation of AutoFill fill window-->
-    <dimen name="autofill_fill_elevation">2dp</dimen>
+    <dimen name="autofill_fill_elevation">4dp</dimen>
     <dimen name="autofill_fill_item_height">64dp</dimen>
+    <dimen name="autofill_fill_min_margin">16dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index ebe577c..e3fdcec 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -149,6 +149,7 @@
     <dimen name="timepicker_radial_picker_dimen">296dp</dimen>
     <dimen name="timepicker_radial_picker_top_margin">16dp</dimen>
     <dimen name="timepicker_radial_picker_horizontal_margin">16dp</dimen>
+    <dimen name="timepicker_edit_text_size">24sp</dimen>
 
     <!-- Used by RadialTimePicker in clock-style TimePicker. -->
     <dimen name="timepicker_selector_radius">20dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d795d80..1dbd567d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2777,7 +2777,7 @@
         <public name="paddingVertical" />
         <public name="visibleToInstantApps" />
         <public name="keyboardNavigationCluster" />
-        <public name="__removed0" />
+        <public name="targetProcess" />
         <public name="nextClusterForward" />
         <public name="__removed1" />
         <public name="textColorError" />
@@ -2792,6 +2792,8 @@
         <public name="isolatedSplits" />
         <public name="targetSandboxVersion" />
         <public name="canCaptureFingerprintGestures" />
+        <public name="alphabeticModifiers" />
+        <public name="numericModifiers" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e00874f..19c5643 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4471,4 +4471,20 @@
     <string name="device_storage_monitor_notification_channel">Device storage</string>
     <!-- Channel name for UsbDeviceManager adb debugging notifications -->
     <string name="adb_debugging_notification_channel_tv">USB debugging</string>
+
+    <!-- Label for the time picker hour input field. [CHAR LIMIT=20] -->
+    <string name="time_picker_hour_label">hour</string>
+    <!-- Label for the time picker minute input field. [CHAR LIMIT=20] -->
+    <string name="time_picker_minute_label">minute</string>
+    <!-- The title for the time picker dialog. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_header_text">Set time</string>
+    <!-- Error shown to the user if they type in invalid hour or minute in the time picker. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_input_error">Enter a valid time</string>
+    <!-- Label shown to the user in time picker to let them know that should type in time. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_prompt_label">Type in time</string>
+    <!-- Accessibility string used for describing the button in time picker that changes the dialog to text input mode. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_text_input_mode_description">Switch to text input mode for the time input.</string>
+    <!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string>
+
 </resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 1e15348..8f061a3 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -426,6 +426,21 @@
         <item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
     </style>
 
+    <style name="TextAppearance.Material.TimePicker.InputHeader" parent="TextAppearance.Material">
+        <item name="textSize">@dimen/text_size_display_1_material</item>
+        <item name="textColor">@color/white</item>
+        <item name="fontFamily">sans-serif-medium</item>
+    </style>
+
+    <style name="TextAppearance.Material.TimePicker.InputField" parent="TextAppearance.Material">
+        <item name="textSize">@dimen/timepicker_edit_text_size</item>
+    </style>
+
+    <style name="TextAppearance.Material.TimePicker.PromptLabel" parent="TextAppearance.Material">
+        <item name="textSize">@dimen/timepicker_text_size_normal</item>
+        <item name="fontFamily">sans-serif-medium</item>
+    </style>
+
     <style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
         <item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
         <item name="textSize">@dimen/date_picker_year_label_size</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b95c20b..89269aa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -120,6 +120,7 @@
   <java-symbol type="id" name="permission_list" />
   <java-symbol type="id" name="pickers" />
   <java-symbol type="id" name="prefs" />
+  <java-symbol type="id" name="prefs_container" />
   <java-symbol type="id" name="prefs_frame" />
   <java-symbol type="id" name="prev" />
   <java-symbol type="id" name="progress" />
@@ -2834,6 +2835,7 @@
   <!-- com.android.server.autofill -->
   <java-symbol type="dimen" name="autofill_fill_elevation" />
   <java-symbol type="dimen" name="autofill_fill_item_height" />
+  <java-symbol type="dimen" name="autofill_fill_min_margin" />
   <java-symbol type="layout" name="autofill_save"/>
   <java-symbol type="id" name="autofill_save_title" />
   <java-symbol type="id" name="autofill_save_no" />
@@ -2842,4 +2844,24 @@
   <!-- Accessibility fingerprint gestures -->
   <java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
   <java-symbol type="string" name="capability_desc_canCaptureFingerprintGestures" />
+
+  <!-- Time picker -->
+  <java-symbol type="id" name="toggle_mode"/>
+  <java-symbol type="id" name="input_mode"/>
+  <java-symbol type="id" name="input_header"/>
+  <java-symbol type="id" name="input_separator"/>
+  <java-symbol type="id" name="input_hour"/>
+  <java-symbol type="id" name="input_minute"/>
+  <java-symbol type="id" name="am_pm_spinner"/>
+  <java-symbol type="id" name="label_hour"/>
+  <java-symbol type="id" name="label_minute"/>
+  <java-symbol type="id" name="label_error"/>
+  <java-symbol type="layout" name="time_picker_text_input_material"/>
+  <java-symbol type="drawable" name="btn_keyboard_key_material"/>
+  <java-symbol type="drawable" name="btn_event_material"/>
+  <java-symbol type="string" name="time_picker_text_input_mode_description"/>
+  <java-symbol type="string" name="time_picker_radial_mode_description"/>
+
+  <!-- resolver activity -->
+  <java-symbol type="drawable" name="resolver_icon_placeholder" />
 </resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index a0a9e01..48b78d4 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -34,7 +34,8 @@
     espresso-core \
     ub-uiautomator \
     platform-test-annotations \
-    compatibility-device-util
+    compatibility-device-util \
+    truth-prebuilt
 
 LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
 LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
new file mode 100644
index 0000000..c6d077d
--- /dev/null
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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 android.app.usage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UsageStatsTest {
+    private UsageStats left;
+    private UsageStats right;
+
+    @Before
+    public void setUp() throws Exception {
+        left = new UsageStats();
+        right = new UsageStats();
+    }
+
+    @Test
+    public void testEarlierBeginTimeTakesPriorityOnAdd() {
+        left.mPackageName = "com.test";
+        left.mBeginTimeStamp = 100000;
+        right.mPackageName = "com.test";
+        right.mBeginTimeStamp = 99999;
+
+        left.add(right);
+
+        assertThat(left.getFirstTimeStamp()).isEqualTo(99999);
+    }
+
+    @Test
+    public void testLaterEndTimeTakesPriorityOnAdd() {
+        left.mPackageName = "com.test";
+        left.mEndTimeStamp = 100000;
+        right.mPackageName = "com.test";
+        right.mEndTimeStamp = 100001;
+
+        left.add(right);
+
+        assertThat(left.getLastTimeStamp()).isEqualTo(100001);
+    }
+
+    @Test
+    public void testLastUsedTimeIsOverriddenByLaterStats() {
+        left.mPackageName = "com.test";
+        left.mBeginTimeStamp = 100000;
+        left.mLastTimeUsed = 200000;
+        right.mPackageName = "com.test";
+        right.mBeginTimeStamp = 100001;
+        right.mLastTimeUsed = 200001;
+
+        left.add(right);
+
+        assertThat(left.getLastTimeUsed()).isEqualTo(200001);
+    }
+
+    @Test
+    public void testLastUsedTimeIsNotOverriddenByLaterStatsIfUseIsEarlier() {
+        left.mPackageName = "com.test";
+        left.mBeginTimeStamp = 100000;
+        left.mLastTimeUsed = 200000;
+        right.mPackageName = "com.test";
+        right.mBeginTimeStamp = 100001;
+        right.mLastTimeUsed = 150000;
+
+        left.add(right);
+
+        assertThat(left.getLastTimeUsed()).isEqualTo(200000);
+    }
+
+    @Test
+    public void testForegroundTimeIsSummed() {
+        left.mPackageName = "com.test";
+        left.mBeginTimeStamp = 100000;
+        left.mTotalTimeInForeground = 10;
+        right.mPackageName = "com.test";
+        right.mBeginTimeStamp = 100001;
+        right.mTotalTimeInForeground = 1;
+
+        left.add(right);
+
+        assertThat(left.getTotalTimeInForeground()).isEqualTo(11);
+    }
+}
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 5bfff26..ce5d3ef 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -19,6 +19,7 @@
 import static org.mockito.Mockito.when;
 
 import android.Manifest.permission;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -30,13 +31,16 @@
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.provider.Settings;
 import android.test.InstrumentationTestCase;
+
 import com.android.internal.R;
-import java.util.List;
+
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
     @Mock private Context mMockContext;
     @Mock private PackageManager mMockPm;
@@ -114,39 +118,40 @@
 
     public void testGetNetworkRecommendationProviderData_scoreNetworksNotGranted()
             throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksDenied("package1");
-        mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+        final ComponentName recoComponent = new ComponentName("package1", "class1");
+        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        mockScoreNetworksDenied(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
 
         assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
     }
 
     public void testGetNetworkRecommendationProviderData_available() throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-        mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+        final ComponentName recoComponent = new ComponentName("package1", "class1");
+        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        mockScoreNetworksGranted(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
 
         NetworkScorerAppData appData =
                 mNetworkScorerAppManager.getNetworkRecommendationProviderData();
         assertNotNull(appData);
-        assertEquals("package1", appData.packageName);
+        assertEquals(recoComponent, appData.getRecommendationServiceComponent());
         assertEquals(924, appData.packageUid);
-        assertEquals(".RecommendationService", appData.recommendationServiceClassName);
     }
 
     public void testGetActiveScorer_providerAvailable() throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-        mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+        final ComponentName recoComponent = new ComponentName("package1", "class1");
+        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        mockScoreNetworksGranted(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
 
         ContentResolver cr = mTargetContext.getContentResolver();
         Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
 
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
-        assertEquals("package1", activeScorer.packageName);
+        assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
         assertEquals(924, activeScorer.packageUid);
-        assertEquals(".RecommendationService", activeScorer.recommendationServiceClassName);
     }
 
     public void testGetActiveScorer_providerNotAvailable()
@@ -159,9 +164,10 @@
     }
 
     public void testGetActiveScorer_recommendationsDisabled() throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-        mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+        final ComponentName recoComponent = new ComponentName("package1", "class1");
+        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        mockScoreNetworksGranted(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
         ContentResolver cr = mTargetContext.getContentResolver();
         Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
 
@@ -187,11 +193,11 @@
                 .thenReturn(PackageManager.PERMISSION_DENIED);
     }
 
-    private void mockRecommendationServiceAvailable(final String packageName, int packageUid) {
+    private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid) {
         final ResolveInfo serviceInfo = new ResolveInfo();
         serviceInfo.serviceInfo = new ServiceInfo();
-        serviceInfo.serviceInfo.name = ".RecommendationService";
-        serviceInfo.serviceInfo.packageName = packageName;
+        serviceInfo.serviceInfo.name = compName.getClassName();
+        serviceInfo.serviceInfo.packageName = compName.getPackageName();
         serviceInfo.serviceInfo.applicationInfo = new ApplicationInfo();
         serviceInfo.serviceInfo.applicationInfo.uid = packageUid;
 
@@ -203,7 +209,7 @@
                         Intent intent = (Intent) object;
                         return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS
                                 .equals(intent.getAction())
-                                && packageName.equals(intent.getPackage());
+                                && compName.getPackageName().equals(intent.getPackage());
                     }
                 }), Mockito.eq(flags))).thenReturn(serviceInfo);
     }
diff --git a/core/tests/coretests/src/android/net/RecommendationRequestTest.java b/core/tests/coretests/src/android/net/RecommendationRequestTest.java
index bd25500..e2e6883 100644
--- a/core/tests/coretests/src/android/net/RecommendationRequestTest.java
+++ b/core/tests/coretests/src/android/net/RecommendationRequestTest.java
@@ -96,7 +96,7 @@
 
         RecommendationRequest parceled = passThroughParcel(request);
 
-        assertEquals(0, parceled.getLastSelectedNetworkId());
+        assertEquals(-1, parceled.getLastSelectedNetworkId());
         assertEquals(0, parceled.getLastSelectedNetworkTimestamp());
     }
 
diff --git a/core/tests/coretests/src/android/provider/SettingsTest.java b/core/tests/coretests/src/android/provider/SettingsTest.java
index d76980a..019f837 100644
--- a/core/tests/coretests/src/android/provider/SettingsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsTest.java
@@ -384,7 +384,6 @@
                  Settings.Secure.AUTO_FILL_SERVICE,
                  Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED,
                  Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
-                 Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DOWNLOADS_DAYS_TO_RETAIN,
                  Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
                  Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
                  Settings.Secure.BACKUP_AUTO_RESTORE,
@@ -392,7 +391,6 @@
                  Settings.Secure.BACKUP_PROVISIONED,
                  Settings.Secure.BACKUP_TRANSPORT,
                  Settings.Secure.BLUETOOTH_HCI_LOG,
-                 Settings.Secure.BRIGHTNESS_USE_TWILIGHT,  // Candidate for backup?
                  Settings.Secure.CARRIER_APPS_HANDLED,
                  Settings.Secure.COMPLETED_CATEGORY_PREFIX,
                  Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
@@ -403,9 +401,6 @@
                  Settings.Secure.DISABLED_PRINT_SERVICES,
                  Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
                  Settings.Secure.DISPLAY_DENSITY_FORCED,
-                 Settings.Secure.DOWNLOADS_BACKUP_ALLOW_METERED,  // Candidate?
-                 Settings.Secure.DOWNLOADS_BACKUP_CHARGING_ONLY, // Candidate?
-                 Settings.Secure.DOWNLOADS_BACKUP_ENABLED, // Candidate?
                  Settings.Secure.DOZE_ALWAYS_ON,
                  Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
                  Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
diff --git a/core/tests/coretests/src/android/transition/FadeTransitionTest.java b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
index dc60423..7e7e815 100644
--- a/core/tests/coretests/src/android/transition/FadeTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
@@ -21,7 +21,7 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.transition.Transition.TransitionListener;
-import android.transition.Transition.TransitionListenerAdapter;
+import android.transition.TransitionListenerAdapter;
 import android.view.View;
 import android.view.ViewGroup;
 
diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java
index a73f5a6..44fcd13 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTest.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTest.java
@@ -16,9 +16,17 @@
 
 package android.view;
 
+import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.graphics.PixelFormat;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.frameworks.coretests.R;
 
 public class ViewAttachTest extends
         ActivityInstrumentationTestCase2<ViewAttachTestActivity> {
@@ -51,4 +59,38 @@
             SystemClock.sleep(250);
         }
     }
+
+    /**
+     * Make sure that on any attached view, if the view is full-screen and hosted
+     * on a round device, the round scrollbars will be displayed even if the activity
+     * window is offset.
+     *
+     * @throws Throwable
+     */
+    @UiThreadTest
+    public void testRoundScrollbars() throws Throwable {
+        final ViewAttachTestActivity activity = getActivity();
+        final View rootView = activity.getWindow().getDecorView();
+        final WindowManager.LayoutParams params =
+            new WindowManager.LayoutParams(
+                rootView.getWidth(),
+                rootView.getHeight(),
+                50, /* xPosition */
+                0, /* yPosition */
+                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+                PixelFormat.TRANSLUCENT);
+
+        rootView.setLayoutParams(params);
+
+        View contentView = activity.findViewById(R.id.view_attach_view);
+        boolean shouldDrawRoundScrollbars = contentView.shouldDrawRoundScrollbar();
+
+        if (activity.getResources().getConfiguration().isScreenRound()) {
+            assertTrue(shouldDrawRoundScrollbars);
+        } else {
+            // Never draw round scrollbars on non-round devices.
+            assertFalse(shouldDrawRoundScrollbars);
+        }
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index dc75417..686f75b 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -364,39 +364,62 @@
     public void testImeSubtypeListComparator() throws Exception {
         {
             final List<ImeSubtypeListItem> items = Arrays.asList(
-                    createDummyItem("X", "A", "en_US", 0, "en_US"),
-                    createDummyItem("X", "A", "en", 1, "en_US"),
-                    createDummyItem("X", "A", "ja", 2, "en_US"),
+                    // Subtypes of IME "X".
+                    // Subtypes that has the same locale of the system's.
+                    createDummyItem("X", "E", "en_US", 0, "en_US"),
                     createDummyItem("X", "Z", "en_US", 3, "en_US"),
-                    createDummyItem("X", "Z", "en", 4, "en_US"),
-                    createDummyItem("X", "Z", "ja", 5, "en_US"),
                     createDummyItem("X", "", "en_US", 6, "en_US"),
+                    // Subtypes that has the same language of the system's.
+                    createDummyItem("X", "E", "en", 1, "en_US"),
+                    createDummyItem("X", "Z", "en", 4, "en_US"),
                     createDummyItem("X", "", "en", 7, "en_US"),
+                    // Subtypes that has different language than the system's.
+                    createDummyItem("X", "A", "hi_IN", 27, "en_US"),
+                    createDummyItem("X", "E", "ja", 2, "en_US"),
+                    createDummyItem("X", "Z", "ja", 5, "en_US"),
                     createDummyItem("X", "", "ja", 8, "en_US"),
-                    createDummyItem("Y", "A", "en_US", 9, "en_US"),
-                    createDummyItem("Y", "A", "en", 10, "en_US"),
-                    createDummyItem("Y", "A", "ja", 11, "en_US"),
+
+                    // Subtypes of IME "Y".
+                    // Subtypes that has the same locale of the system's.
+                    createDummyItem("Y", "E", "en_US", 9, "en_US"),
                     createDummyItem("Y", "Z", "en_US", 12, "en_US"),
-                    createDummyItem("Y", "Z", "en", 13, "en_US"),
-                    createDummyItem("Y", "Z", "ja", 14, "en_US"),
                     createDummyItem("Y", "", "en_US", 15, "en_US"),
+                    // Subtypes that has the same language of the system's.
+                    createDummyItem("Y", "E", "en", 10, "en_US"),
+                    createDummyItem("Y", "Z", "en", 13, "en_US"),
                     createDummyItem("Y", "", "en", 16, "en_US"),
+                    // Subtypes that has different language than the system's.
+                    createDummyItem("Y", "A", "hi_IN", 28, "en_US"),
+                    createDummyItem("Y", "E", "ja", 11, "en_US"),
+                    createDummyItem("Y", "Z", "ja", 14, "en_US"),
                     createDummyItem("Y", "", "ja", 17, "en_US"),
-                    createDummyItem("", "A", "en_US", 18, "en_US"),
-                    createDummyItem("", "A", "en", 19, "en_US"),
-                    createDummyItem("", "A", "ja", 20, "en_US"),
+
+                    // Subtypes of IME "".
+                    // Subtypes that has the same locale of the system's.
+                    createDummyItem("", "E", "en_US", 18, "en_US"),
                     createDummyItem("", "Z", "en_US", 21, "en_US"),
-                    createDummyItem("", "Z", "en", 22, "en_US"),
-                    createDummyItem("", "Z", "ja", 23, "en_US"),
                     createDummyItem("", "", "en_US", 24, "en_US"),
+                    // Subtypes that has the same language of the system's.
+                    createDummyItem("", "E", "en", 19, "en_US"),
+                    createDummyItem("", "Z", "en", 22, "en_US"),
                     createDummyItem("", "", "en", 25, "en_US"),
+                    // Subtypes that has different language than the system's.
+                    createDummyItem("", "A", "hi_IN", 29, "en_US"),
+                    createDummyItem("", "E", "ja", 20, "en_US"),
+                    createDummyItem("", "Z", "ja", 23, "en_US"),
                     createDummyItem("", "", "ja", 26, "en_US"));
 
+            // Ensure {@link java.lang.Comparable#compareTo} contracts are satisfied.
             for (int i = 0; i < items.size(); ++i) {
-                assertEquals(0, items.get(i).compareTo(items.get(i)));
+                final ImeSubtypeListItem item1 = items.get(i);
+                // Ensures sgn(x.compareTo(y)) == -sgn(y.compareTo(x)).
+                assertTrue(item1 + " has the same order of itself", item1.compareTo(item1) == 0);
+                // Ensures (x.compareTo(y) > 0 && y.compareTo(z) > 0) implies x.compareTo(z) > 0.
                 for (int j = i + 1; j < items.size(); ++j) {
-                    assertTrue(items.get(i).compareTo(items.get(j)) < 0);
-                    assertTrue(items.get(j).compareTo(items.get(i)) > 0);
+                    final ImeSubtypeListItem item2 = items.get(j);
+                    // Ensures sgn(x.compareTo(y)) == -sgn(y.compareTo(x)).
+                    assertTrue(item1 + " is less than " + item2, item1.compareTo(item2) < 0);
+                    assertTrue(item2 + " is greater than " + item1, item2.compareTo(item1) > 0);
                 }
             }
         }
@@ -404,11 +427,14 @@
         {
             // Following two items have the same priority.
             final ImeSubtypeListItem nonSystemLocale1 =
-                    createDummyItem("X", "A", "ja_JP", 0, "en_us");
+                    createDummyItem("X", "A", "ja_JP", 0, "en_US");
             final ImeSubtypeListItem nonSystemLocale2 =
-                    createDummyItem("X", "A", "hi_IN", 1, "en_us");
-            assertEquals(0, nonSystemLocale1.compareTo(nonSystemLocale2));
-            assertEquals(0, nonSystemLocale2.compareTo(nonSystemLocale1));
+                    createDummyItem("X", "A", "hi_IN", 1, "en_US");
+            assertTrue(nonSystemLocale1.compareTo(nonSystemLocale2) == 0);
+            assertTrue(nonSystemLocale2.compareTo(nonSystemLocale1) == 0);
+            // But those aren't equal to each other.
+            assertFalse(nonSystemLocale1.equals(nonSystemLocale2));
+            assertFalse(nonSystemLocale2.equals(nonSystemLocale1));
         }
     }
 }
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
index 62ef25b..7fafef7 100644
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -23,4 +23,9 @@
     <allow-implicit-broadcast action="android.intent.action.PACKAGE_CHANGED" />
     <allow-implicit-broadcast action="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
 
+    <!-- Whitelist of what components are permitted as backup data transports.  The
+         'service' attribute here is a flattened ComponentName string. -->
+    <backup-transport-whitelisted-service
+        service="android/com.android.internal.backup.LocalTransportService" />
+
 </config>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index e46f166..b394c3c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -155,6 +155,7 @@
     <assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
     <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
+    <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="cameraserver" />
 
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
 
@@ -176,6 +177,9 @@
          access while in data mode, even if they aren't in the foreground. -->
     <allow-in-data-usage-save package="com.android.providers.downloads" />
 
+    <!-- This is a core platform component that needs to freely run in the background -->
+    <allow-in-power-save package="com.android.cellbroadcastreceiver" />
+
     <!-- These are the packages that are white-listed to be able to run as system user -->
     <system-user-whitelisted-app package="com.android.settings" />
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c5961ab..039ab1f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -132,6 +132,7 @@
         <permission name="android.permission.ACCESS_IMS_CALL_SERVICE"/>
         <permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/>
         <permission name="android.permission.BIND_CARRIER_SERVICES"/>
+        <permission name="android.permission.BIND_IMS_SERVICE"/>
         <permission name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"/>
         <permission name="android.permission.CALL_PRIVILEGED"/>
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
@@ -339,4 +340,4 @@
         <permission name="android.permission.CONTROL_VPN"/>
     </privapp-permissions>
 
-</permissions>
\ No newline at end of file
+</permissions>
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index f5cedfa..b490545 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -583,4 +583,17 @@
         right = in.readFloat();
         bottom = in.readFloat();
     }
+
+    /**
+     * Scales up the rect by the given scale.
+     * @hide
+     */
+    public void scale(float scale) {
+        if (scale != 1.0f) {
+            left = left * scale;
+            top = top * scale ;
+            right = right * scale;
+            bottom = bottom * scale;
+        }
+    }
 }
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 5531871..750ef3f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -198,9 +198,10 @@
     }
 
     /**
+     * Used by resources for cached loading if the font is available.
      * @hide
      */
-    public static Typeface createFromCache(AssetManager mgr, String path) {
+    public static Typeface findFromCache(AssetManager mgr, String path) {
         synchronized (sDynamicTypefaceCache) {
             final String key = createAssetUid(mgr, path);
             Typeface typeface = sDynamicTypefaceCache.get(key);
@@ -221,6 +222,15 @@
      * @param callback A callback that will be triggered when results are obtained. May not be null.
      */
     public static void create(@NonNull FontRequest request, @NonNull FontRequestCallback callback) {
+        // Check the cache first
+        // TODO: would the developer want to avoid a cache hit and always ask for the freshest
+        // result?
+        Typeface cachedTypeface = findFromCache(
+                request.getProviderAuthority(), request.getQuery());
+        if (cachedTypeface != null) {
+            mHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
+            return;
+        }
         synchronized (sLock) {
             if (sFontsContract == null) {
                 sFontsContract = new FontsContract();
@@ -229,20 +239,34 @@
             final ResultReceiver receiver = new ResultReceiver(null) {
                 @Override
                 public void onReceiveResult(int resultCode, Bundle resultData) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            receiveResult(request, callback, resultCode, resultData);
-                        }
-                    });
+                    mHandler.post(() -> receiveResult(request, callback, resultCode, resultData));
                 }
             };
             sFontsContract.getFont(request, receiver);
         }
     }
 
+    private static Typeface findFromCache(String providerAuthority, String query) {
+        synchronized (sDynamicTypefaceCache) {
+            final String key = createProviderUid(providerAuthority, query);
+            Typeface typeface = sDynamicTypefaceCache.get(key);
+            if (typeface != null) {
+                return typeface;
+            }
+        }
+        return null;
+    }
+
     private static void receiveResult(FontRequest request, FontRequestCallback callback,
             int resultCode, Bundle resultData) {
+        Typeface cachedTypeface = findFromCache(
+                request.getProviderAuthority(), request.getQuery());
+        if (cachedTypeface != null) {
+            // We already know the result.
+            // Probably the requester requests the same font again in a short interval.
+            callback.onTypefaceRetrieved(cachedTypeface);
+            return;
+        }
         if (resultCode == FontsContract.RESULT_CODE_PROVIDER_NOT_FOUND) {
             callback.onTypefaceRequestFailed(
                     FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND);
@@ -296,8 +320,12 @@
             }
         }
         fontFamily.freeze();
-        callback.onTypefaceRetrieved(Typeface.createFromFamiliesWithDefault(
-                new FontFamily[] {fontFamily}));
+        Typeface typeface = Typeface.createFromFamiliesWithDefault(new FontFamily[] { fontFamily });
+        synchronized (sDynamicTypefaceCache) {
+            String key = createProviderUid(request.getProviderAuthority(), request.getQuery());
+            sDynamicTypefaceCache.put(key, typeface);
+        }
+        callback.onTypefaceRetrieved(typeface);
     }
 
     /**
@@ -464,6 +492,7 @@
     private static String createAssetUid(final AssetManager mgr, String path) {
         final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
         final StringBuilder builder = new StringBuilder();
+        builder.append("asset:");
         final int size = pkgs.size();
         for (int i = 0; i < size; i++) {
             builder.append(pkgs.valueAt(i));
@@ -474,6 +503,18 @@
     }
 
     /**
+     * Creates a unique id for a given font provider and query.
+     */
+    private static String createProviderUid(String authority, String query) {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("provider:");
+        builder.append(authority);
+        builder.append("-");
+        builder.append(query);
+        return builder.toString();
+    }
+
+    /**
      * Create a new typeface from the specified font file.
      *
      * @param path The path to the font data.
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index ecf6bd4..e764034 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -36,6 +36,7 @@
         "misc.cpp",
         "ObbFile.cpp",
         "ResourceTypes.cpp",
+        "ResourceUtils.cpp",
         "StreamingZipInflater.cpp",
         "TypeWrappers.cpp",
         "Util.cpp",
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 542a125..ef0c967 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -31,6 +31,8 @@
 #endif
 #endif
 
+#include "androidfw/ResourceUtils.h"
+
 namespace android {
 
 AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); }
@@ -235,9 +237,9 @@
     desired_config = &density_override_config;
   }
 
-  const uint32_t package_id = util::get_package_id(resid);
-  const uint8_t type_id = util::get_type_id(resid);
-  const uint16_t entry_id = util::get_entry_id(resid);
+  const uint32_t package_id = get_package_id(resid);
+  const uint8_t type_id = get_type_id(resid);
+  const uint16_t entry_id = get_entry_id(resid);
 
   if (type_id == 0) {
     LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
@@ -452,7 +454,7 @@
     ResolvedBag::Entry* new_entry = new_bag->entries;
     for (; map_entry != map_entry_end; ++map_entry) {
       uint32_t new_key = dtohl(map_entry->name.ident);
-      if (!util::is_internal_resid(new_key)) {
+      if (!is_internal_resid(new_key)) {
         // Attributes, arrays, etc don't have a resource id as the name. They specify
         // other data, which would be wrong to change via a lookup.
         if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
@@ -501,7 +503,7 @@
   // The keys are expected to be in sorted order. Merge the two bags.
   while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
     uint32_t child_key = dtohl(map_entry->name.ident);
-    if (!util::is_internal_resid(child_key)) {
+    if (!is_internal_resid(child_key)) {
       if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
         LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid);
         return nullptr;
@@ -533,7 +535,7 @@
   // Finish the child entries if they exist.
   while (map_entry != map_entry_end) {
     uint32_t new_key = dtohl(map_entry->name.ident);
-    if (!util::is_internal_resid(new_key)) {
+    if (!is_internal_resid(new_key)) {
       if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
         LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
         return nullptr;
@@ -571,12 +573,71 @@
   return result;
 }
 
+static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) {
+  ssize_t len =
+      utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str.data()), str.size(), false);
+  if (len < 0) {
+    return false;
+  }
+  out->resize(static_cast<size_t>(len));
+  utf8_to_utf16(reinterpret_cast<const uint8_t*>(str.data()), str.size(), &*out->begin(),
+                static_cast<size_t>(len + 1));
+  return true;
+}
+
 uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
                                       const std::string& fallback_type,
                                       const std::string& fallback_package) {
-  (void)resource_name;
-  (void)fallback_type;
-  (void)fallback_package;
+  StringPiece package_name, type, entry;
+  if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
+    return 0u;
+  }
+
+  if (entry.empty()) {
+    return 0u;
+  }
+
+  if (package_name.empty()) {
+    package_name = fallback_package;
+  }
+
+  if (type.empty()) {
+    type = fallback_type;
+  }
+
+  std::u16string type16;
+  if (!Utf8ToUtf16(type, &type16)) {
+    return 0u;
+  }
+
+  std::u16string entry16;
+  if (!Utf8ToUtf16(entry, &entry16)) {
+    return 0u;
+  }
+
+  const StringPiece16 kAttr16 = u"attr";
+  const static std::u16string kAttrPrivate16 = u"^attr-private";
+
+  for (const PackageGroup& package_group : package_groups_) {
+    for (const LoadedPackage* package : package_group.packages_) {
+      if (package_name != package->GetPackageName()) {
+        // All packages in the same group are expected to have the same package name.
+        break;
+      }
+
+      uint32_t resid = package->FindEntryByName(type16, entry16);
+      if (resid == 0u && kAttr16 == type16) {
+        // Private attributes in libraries (such as the framework) are sometimes encoded
+        // under the type '^attr-private' in order to leave the ID space of public 'attr'
+        // free for future additions. Check '^attr-private' for the same name.
+        resid = package->FindEntryByName(kAttrPrivate16, entry16);
+      }
+
+      if (resid != 0u) {
+        return fix_package_id(resid, package_group.dynamic_ref_table.mAssignedPackageId);
+      }
+    }
+  }
   return 0u;
 }
 
@@ -619,15 +680,15 @@
 
     // If the resource ID passed in is not a style, the key can be
     // some other identifier that is not a resource ID.
-    if (!util::is_valid_resid(attr_resid)) {
+    if (!is_valid_resid(attr_resid)) {
       return false;
     }
 
-    const uint32_t package_idx = util::get_package_id(attr_resid);
+    const uint32_t package_idx = get_package_id(attr_resid);
 
     // The type ID is 1-based, so subtract 1 to get an index.
-    const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
-    const uint32_t entry_idx = util::get_entry_id(attr_resid);
+    const uint32_t type_idx = get_type_id(attr_resid) - 1;
+    const uint32_t entry_idx = get_entry_id(attr_resid);
 
     std::unique_ptr<Package>& package = packages_[package_idx];
     if (package == nullptr) {
@@ -656,9 +717,9 @@
   // and populate the structures.
   for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
     const uint32_t attr_resid = bag_iter->key;
-    const uint32_t package_idx = util::get_package_id(attr_resid);
-    const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
-    const uint32_t entry_idx = util::get_entry_id(attr_resid);
+    const uint32_t package_idx = get_package_id(attr_resid);
+    const uint32_t type_idx = get_type_id(attr_resid) - 1;
+    const uint32_t entry_idx = get_entry_id(attr_resid);
     Package* package = packages_[package_idx].get();
     util::unique_cptr<Type>& type = package->types[type_idx];
     if (type->entry_count != type->entry_capacity) {
@@ -691,15 +752,15 @@
   uint32_t type_spec_flags = 0u;
 
   for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) {
-    if (!util::is_valid_resid(resid)) {
+    if (!is_valid_resid(resid)) {
       return kInvalidCookie;
     }
 
-    const uint32_t package_idx = util::get_package_id(resid);
+    const uint32_t package_idx = get_package_id(resid);
 
     // Type ID is 1-based, subtract 1 to get the index.
-    const uint32_t type_idx = util::get_type_id(resid) - 1;
-    const uint32_t entry_idx = util::get_entry_id(resid);
+    const uint32_t type_idx = get_type_id(resid) - 1;
+    const uint32_t entry_idx = get_entry_id(resid);
 
     const Package* package = packages_[package_idx].get();
     if (package == nullptr) {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index cb589ec..db72f48 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -34,6 +34,7 @@
 
 #include "androidfw/ByteBucketArray.h"
 #include "androidfw/Chunk.h"
+#include "androidfw/ResourceUtils.h"
 #include "androidfw/Util.h"
 
 using android::base::StringPrintf;
@@ -181,9 +182,9 @@
                            LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
                            uint32_t* out_flags) const {
   ATRACE_CALL();
-  const uint8_t package_id = util::get_package_id(resid);
-  const uint8_t type_id = util::get_type_id(resid);
-  const uint16_t entry_id = util::get_entry_id(resid);
+  const uint8_t package_id = get_package_id(resid);
+  const uint8_t type_id = get_type_id(resid);
+  const uint16_t entry_id = get_entry_id(resid);
 
   if (type_id == 0) {
     LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << ".";
@@ -200,7 +201,7 @@
 }
 
 const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
-  const uint8_t package_id = util::get_package_id(resid);
+  const uint8_t package_id = get_package_id(resid);
   for (const auto& loaded_package : packages_) {
     if (loaded_package->package_id_ == package_id) {
       return loaded_package.get();
@@ -372,6 +373,45 @@
   }
 }
 
+uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name,
+                                        const std::u16string& entry_name) const {
+  ssize_t type_idx = type_string_pool_.indexOfString(type_name.data(), type_name.size());
+  if (type_idx < 0) {
+    return 0u;
+  }
+
+  ssize_t key_idx = key_string_pool_.indexOfString(entry_name.data(), entry_name.size());
+  if (key_idx < 0) {
+    return 0u;
+  }
+
+  const TypeSpec* type_spec = type_specs_[type_idx].get();
+  if (type_spec == nullptr) {
+    return 0u;
+  }
+
+  for (size_t ti = 0; ti < type_spec->type_count; ti++) {
+    const Type* type = &type_spec->types[ti];
+    size_t entry_count = dtohl(type->type->entryCount);
+    for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
+      const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
+          reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
+      const uint32_t offset = dtohl(entry_offsets[entry_idx]);
+      if (offset != ResTable_type::NO_ENTRY) {
+        const ResTable_entry* entry =
+            reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) +
+                                                    dtohl(type->type->entriesStart) + offset);
+        if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
+          // The package ID will be overridden by the caller (due to runtime assignment of package
+          // IDs for shared libraries).
+          return make_resid(0x00, type_idx + type_id_offset_ + 1, entry_idx);
+        }
+      }
+    }
+  }
+  return 0u;
+}
+
 std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
   ATRACE_CALL();
   std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()};
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
new file mode 100644
index 0000000..1aa6cf6
--- /dev/null
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/ResourceUtils.h"
+
+namespace android {
+
+bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
+                         StringPiece* out_entry) {
+  *out_package = "";
+  *out_type = "";
+  bool has_package_separator = false;
+  bool has_type_separator = false;
+  const char* start = str.data();
+  const char* end = start + str.size();
+  const char* current = start;
+  while (current != end) {
+    if (out_type->size() == 0 && *current == '/') {
+      has_type_separator = true;
+      out_type->assign(start, current - start);
+      start = current + 1;
+    } else if (out_package->size() == 0 && *current == ':') {
+      has_package_separator = true;
+      out_package->assign(start, current - start);
+      start = current + 1;
+    }
+    current++;
+  }
+  out_entry->assign(start, end - start);
+
+  return !(has_package_separator && out_package->empty()) &&
+         !(has_type_separator && out_type->empty());
+}
+
+}  // namespace android
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 91a7cb7..f30b158 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -101,6 +101,13 @@
   // before being inserted into the set. This may cause some equivalent locales to de-dupe.
   void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
 
+  // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
+  // the underlying ResStringPool API expects this. For now this is acceptable, but since
+  // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
+  // Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
+  // for patching the correct package ID to the resource ID.
+  uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
 
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
new file mode 100644
index 0000000..6bf7c24
--- /dev/null
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROIDFW_RESOURCEUTILS_H
+#define ANDROIDFW_RESOURCEUTILS_H
+
+#include "androidfw/StringPiece.h"
+
+namespace android {
+
+// Extracts the package, type, and name from a string of the format: [[package:]type/]name
+// Validation must be performed on each extracted piece.
+// Returns false if there was a syntax error.
+bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
+                         StringPiece* out_entry);
+
+inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
+  return resid | (static_cast<uint32_t>(package_id) << 24);
+}
+
+inline uint8_t get_package_id(uint32_t resid) {
+  return static_cast<uint8_t>((resid >> 24) & 0x000000ffu);
+}
+
+// The type ID is 1-based, so if the returned value is 0 it is invalid.
+inline uint8_t get_type_id(uint32_t resid) {
+  return static_cast<uint8_t>((resid >> 16) & 0x000000ffu);
+}
+
+inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); }
+
+inline bool is_internal_resid(uint32_t resid) {
+  return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0;
+}
+
+inline bool is_valid_resid(uint32_t resid) {
+  return (resid & 0x00ff0000u) != 0 && (resid & 0xff000000u) != 0;
+}
+
+inline uint32_t make_resid(uint8_t package_id, uint8_t type_id, uint16_t entry_id) {
+  return (static_cast<uint32_t>(package_id) << 24) | (static_cast<uint32_t>(type_id) << 16) |
+         entry_id;
+}
+
+}  // namespace android
+
+#endif /* ANDROIDFW_RESOURCEUTILS_H */
diff --git a/libs/androidfw/include/androidfw/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h
index c9effd1..a873d66 100644
--- a/libs/androidfw/include/androidfw/StringPiece.h
+++ b/libs/androidfw/include/androidfw/StringPiece.h
@@ -257,12 +257,50 @@
   return data_ + length_;
 }
 
+template <typename TChar>
+inline bool operator==(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
+  return BasicStringPiece<TChar>(lhs) == rhs;
+}
+
+template <typename TChar>
+inline bool operator!=(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
+  return BasicStringPiece<TChar>(lhs) != rhs;
+}
+
 inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
   return out.write(str.data(), str.size());
 }
 
+template <typename TChar>
+inline ::std::basic_string<TChar>& operator+=(::std::basic_string<TChar>& lhs,
+                                              const BasicStringPiece<TChar>& rhs) {
+  return lhs.append(rhs.data(), rhs.size());
+}
+
+template <typename TChar>
+inline bool operator==(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
+  return rhs == lhs;
+}
+
+template <typename TChar>
+inline bool operator!=(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
+  return rhs != lhs;
+}
+
 }  // namespace android
 
+inline ::std::ostream& operator<<(::std::ostream& out, const std::u16string& str) {
+  ssize_t utf8_len = utf16_to_utf8_length(str.data(), str.size());
+  if (utf8_len < 0) {
+    return out << "???";
+  }
+
+  std::string utf8;
+  utf8.resize(static_cast<size_t>(utf8_len));
+  utf16_to_utf8(str.data(), str.size(), &*utf8.begin(), utf8_len + 1);
+  return out << utf8;
+}
+
 namespace std {
 
 template <typename TChar>
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index 96b42bf..3950cf2 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -106,29 +106,6 @@
   pointer ptr_;
 };
 
-inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
-  return resid | (static_cast<uint32_t>(package_id) << 24);
-}
-
-inline uint8_t get_package_id(uint32_t resid) {
-  return static_cast<uint8_t>((resid >> 24) & 0x000000ffu);
-}
-
-// The type ID is 1-based, so if the returned value is 0 it is invalid.
-inline uint8_t get_type_id(uint32_t resid) {
-  return static_cast<uint8_t>((resid >> 16) & 0x000000ffu);
-}
-
-inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); }
-
-inline bool is_internal_resid(uint32_t resid) {
-  return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0;
-}
-
-inline bool is_valid_resid(uint32_t resid) {
-  return (resid & 0x00ff0000u) != 0 && (resid & 0xff000000u) != 0;
-}
-
 void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out);
 
 }  // namespace util
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 650f813..19527c5 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -32,6 +32,7 @@
     ConfigLocale_test.cpp \
     Idmap_test.cpp \
     LoadedArsc_test.cpp \
+    ResourceUtils_test.cpp \
     ResTable_test.cpp \
     Split_test.cpp \
     StringPiece_test.cpp \
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 557d8d4..78fbb0f 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -20,6 +20,7 @@
 #include "android-base/logging.h"
 
 #include "TestHelpers.h"
+#include "androidfw/ResourceUtils.h"
 #include "data/appaslib/R.h"
 #include "data/basic/R.h"
 #include "data/lib_one/R.h"
@@ -194,11 +195,11 @@
   ResTable_config selected_config;
   uint32_t flags;
   ApkAssetsCookie cookie = assetmanager.GetResource(
-      util::fix_package_id(appaslib::R::integer::number1, 0x02), false /*may_be_bag*/,
+      fix_package_id(appaslib::R::integer::number1, 0x02), false /*may_be_bag*/,
       0u /*density_override*/, &value, &selected_config, &flags);
   ASSERT_NE(kInvalidCookie, cookie);
   EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
-  EXPECT_EQ(util::fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data);
+  EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data);
 }
 
 TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) {
@@ -238,9 +239,9 @@
 
   // First two attributes come from lib_one.
   EXPECT_EQ(1, bag->entries[0].cookie);
-  EXPECT_EQ(0x03, util::get_package_id(bag->entries[0].key));
+  EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
   EXPECT_EQ(1, bag->entries[1].cookie);
-  EXPECT_EQ(0x03, util::get_package_id(bag->entries[1].key));
+  EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
 }
 
 TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
diff --git a/libs/androidfw/tests/ResourceUtils_test.cpp b/libs/androidfw/tests/ResourceUtils_test.cpp
new file mode 100644
index 0000000..b64a884
--- /dev/null
+++ b/libs/androidfw/tests/ResourceUtils_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/ResourceUtils.h"
+
+#include "TestHelpers.h"
+
+namespace android {
+
+TEST(ResourceUtilsTest, ExtractResourceName) {
+  StringPiece package, type, entry;
+  ASSERT_TRUE(ExtractResourceName("android:string/foo", &package, &type, &entry));
+  EXPECT_EQ("android", package);
+  EXPECT_EQ("string", type);
+  EXPECT_EQ("foo", entry);
+
+  ASSERT_TRUE(ExtractResourceName("string/foo", &package, &type, &entry));
+  EXPECT_EQ("", package);
+  EXPECT_EQ("string", type);
+  EXPECT_EQ("foo", entry);
+
+  ASSERT_TRUE(ExtractResourceName("foo", &package, &type, &entry));
+  EXPECT_EQ("", package);
+  EXPECT_EQ("", type);
+  EXPECT_EQ("foo", entry);
+
+  ASSERT_TRUE(ExtractResourceName("android:foo", &package, &type, &entry));
+  EXPECT_EQ("android", package);
+  EXPECT_EQ("", type);
+  EXPECT_EQ("foo", entry);
+
+  EXPECT_FALSE(ExtractResourceName(":string/foo", &package, &type, &entry));
+  EXPECT_FALSE(ExtractResourceName("/foo", &package, &type, &entry));
+}
+
+}  // namespace android
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index daed28b..dfff9c0 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -19,6 +19,7 @@
 #include "android-base/logging.h"
 
 #include "TestHelpers.h"
+#include "androidfw/ResourceUtils.h"
 #include "data/lib_one/R.h"
 #include "data/libclient/R.h"
 #include "data/styles/R.h"
@@ -215,9 +216,9 @@
   EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
 
   // lib_one is assigned package ID 0x03.
-  EXPECT_EQ(3u, util::get_package_id(value.data));
-  EXPECT_EQ(util::get_type_id(lib_one::R::string::foo), util::get_type_id(value.data));
-  EXPECT_EQ(util::get_entry_id(lib_one::R::string::foo), util::get_entry_id(value.data));
+  EXPECT_EQ(3u, get_package_id(value.data));
+  EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value.data));
+  EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value.data));
 }
 
 TEST_F(ThemeTest, CopyThemeSameAssetManager) {
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a799fdf..692199d 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -192,7 +192,7 @@
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
     hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
     hwui_c_includes += \
-        $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) \
+        $(call intermediates-dir-for,STATIC_LIBRARIES,TARGET,) \
         frameworks/rs/cpp \
         frameworks/rs
 endif
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 8a6e038..5cf52c6 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -605,6 +605,7 @@
         } else {
             mDescription.hasExternalTexture = true;
         }
+        mDescription.hasLinearTexture = mOutGlop->fill.texture.texture->isLinear();
     }
 
     mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 1dad58f..71bee93 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -205,6 +205,10 @@
     *d++ = a * (start.g * oppAmount + end.g * amount);
     *d++ = a * (start.b * oppAmount + end.b * amount);
 #else
+    // What we're doing to the alpha channel here is technically incorrect
+    // but reproduces Android's old behavior when the alpha was pre-multiplied
+    // with gamma-encoded colors
+    a = EOCF_sRGB(a);
     *d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount);
     *d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount);
     *d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount);
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index e70982f..5c8f8e9 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -87,6 +87,7 @@
 #define PROGRAM_HAS_ROUND_RECT_CLIP 43
 
 #define PROGRAM_HAS_GAMMA_CORRECTION 44
+#define PROGRAM_HAS_LINEAR_TEXTURE 45
 
 ///////////////////////////////////////////////////////////////////////////////
 // Types
@@ -162,7 +163,10 @@
     bool hasDebugHighlight;
     bool hasRoundRectClip;
 
+    // Extra gamma correction used for text
     bool hasGammaCorrection;
+    // Set when sampling an image in linear space
+    bool hasLinearTexture;
 
     /**
      * Resets this description. All fields are reset back to the default
@@ -205,6 +209,7 @@
         hasRoundRectClip = false;
 
         hasGammaCorrection = false;
+        hasLinearTexture = false;
     }
 
     /**
@@ -275,6 +280,7 @@
         if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
         if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP;
         if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
+        if (hasLinearTexture) key |= programid(0x1) << PROGRAM_HAS_LINEAR_TEXTURE;
         return key;
     }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 7107679..ca05648 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -161,27 +161,54 @@
         "uniform vec4 roundRectInnerRectLTRB;\n"
         "uniform float roundRectRadius;\n";
 
+const char* gFS_OETF[2] = {
+         "\nvec4 OETF(const vec4 linear) {\n"
+         "    return linear;\n"
+         "}\n",
+          // We expect linear data to be scRGB so we mirror the gamma function
+         "\nvec4 OETF(const vec4 linear) {"
+          "    return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);\n"
+          "}\n",
+};
+
+const char* gFS_Transfer_Functions = R"__SHADER__(
+        float OETF_sRGB(const float linear) {
+            // IEC 61966-2-1:1999
+            return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+        }
+
+        vec3 OETF_sRGB(const vec3 linear) {
+            return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+        }
+
+        float EOTF_sRGB(float srgb) {
+            // IEC 61966-2-1:1999
+            return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+        }
+)__SHADER__";
+
 // Dithering must be done in the quantization space
 // When we are writing to an sRGB framebuffer, we must do the following:
-//     EOCF(OECF(color) + dither)
-// We approximate the transfer functions with gamma 2.0 to avoid branches and pow()
+//     EOTF(OETF(color) + dither)
 // The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0]
 // TODO: Handle linear fp16 render targets
-const char* gFS_Gradient_Functions =
-        "\nfloat triangleNoise(const highp vec2 n) {\n"
-        "    highp vec2 p = fract(n * vec2(5.3987, 5.4421));\n"
-        "    p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));\n"
-        "    highp float xy = p.x * p.y;\n"
-        "    return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n"
-        "}\n";
+const char* gFS_Gradient_Functions = R"__SHADER__(
+        float triangleNoise(const highp vec2 n) {
+            highp vec2 p = fract(n * vec2(5.3987, 5.4421));
+            p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
+            highp float xy = p.x * p.y;
+            return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
+        }
+)__SHADER__";
 const char* gFS_Gradient_Preamble[2] = {
         // Linear framebuffer
         "\nvec4 dither(const vec4 color) {\n"
         "    return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n"
         "}\n"
         "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
-        "    vec4 c = pow(mix(a, b, v), vec4(vec3(1.0 / 2.2), 1.0));\n"
-        "    return vec4(c.rgb * c.a, c.a);\n"
+        "    vec4 c = mix(a, b, v);\n"
+        "    c.a = EOTF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility
+        "    return vec4(OETF_sRGB(c.rgb) * c.a, c.a);\n"
         "}\n",
         // sRGB framebuffer
         "\nvec4 dither(const vec4 color) {\n"
@@ -200,13 +227,15 @@
 // The gamma coefficient is chosen to thicken or thin the text accordingly
 // The dot product used to compute the luminance could be approximated with
 // a simple max(color.r, color.g, color.b)
-const char* gFS_Gamma_Preamble =
-        "\n#define GAMMA (%.2f)\n"
-        "#define GAMMA_INV (%.2f)\n"
-        "\nfloat gamma(float a, const vec3 color) {\n"
-        "    float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));\n"
-        "    return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);\n"
-        "}\n";
+const char* gFS_Gamma_Preamble = R"__SHADER__(
+        #define GAMMA (%.2f)
+        #define GAMMA_INV (%.2f)
+
+        float gamma(float a, const vec3 color) {
+            float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
+            return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);
+        }
+)__SHADER__";
 
 const char* gFS_Main =
         "\nvoid main(void) {\n"
@@ -215,52 +244,6 @@
 const char* gFS_Main_AddDither =
         "    fragColor = dither(fragColor);\n";
 
-// Fast cases
-const char* gFS_Fast_SingleColor =
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = color;\n"
-        "}\n\n";
-const char* gFS_Fast_SingleTexture =
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
-        "}\n\n";
-const char* gFS_Fast_SingleModulateTexture =
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = color.a * texture2D(baseSampler, outTexCoords);\n"
-        "}\n\n";
-const char* gFS_Fast_SingleA8Texture =
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
-        "}\n\n";
-const char* gFS_Fast_SingleA8Texture_ApplyGamma =
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(baseSampler, outTexCoords).a, GAMMA));\n"
-        "}\n\n";
-const char* gFS_Fast_SingleModulateA8Texture =
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = color * texture2D(baseSampler, outTexCoords).a;\n"
-        "}\n\n";
-const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = color * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n"
-        "}\n\n";
-const char* gFS_Fast_SingleGradient[2] = {
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = dither(texture2D(gradientSampler, linear));\n"
-        "}\n\n",
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = dither(gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0)));\n"
-        "}\n\n",
-};
-const char* gFS_Fast_SingleModulateGradient[2] = {
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = dither(color.a * texture2D(gradientSampler, linear));\n"
-        "}\n\n",
-        "\nvoid main(void) {\n"
-        "    gl_FragColor = dither(color.a * gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0)));\n"
-        "}\n\n"
-};
-
 // General case
 const char* gFS_Main_FetchColor =
         "    fragColor = color;\n";
@@ -273,7 +256,7 @@
         "    fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n";
 const char* gFS_Main_FetchTexture[2] = {
         // Don't modulate
-        "    fragColor = texture2D(baseSampler, outTexCoords);\n",
+        "    fragColor = OETF(texture2D(baseSampler, outTexCoords));\n",
         // Modulate
         "    fragColor = color * texture2D(baseSampler, outTexCoords);\n"
 };
@@ -304,9 +287,9 @@
         "    vec4 gradientColor = gammaMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
 };
 const char* gFS_Main_FetchBitmap =
-        "    vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
+        "    vec4 bitmapColor = OETF(texture2D(bitmapSampler, outBitmapTexCoords));\n";
 const char* gFS_Main_FetchBitmapNpot =
-        "    vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
+        "    vec4 bitmapColor = OETF(texture2D(bitmapSampler, wrap(outBitmapTexCoords)));\n";
 const char* gFS_Main_BlendShadersBG =
         "    fragColor = blendShaders(gradientColor, bitmapColor)";
 const char* gFS_Main_BlendShadersGB =
@@ -632,71 +615,6 @@
         shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma, 1.0f / Properties::textGamma);
     }
 
-    // Optimization for common cases
-    if (!description.hasVertexAlpha
-            && !blendFramebuffer
-            && !description.hasColors
-            && description.colorOp == ProgramDescription::ColorFilterMode::None
-            && !description.hasDebugHighlight
-            && !description.hasRoundRectClip) {
-        bool fast = false;
-
-        const bool noShader = !description.hasGradient && !description.hasBitmap;
-        const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
-                !description.hasAlpha8Texture && noShader;
-        const bool singleA8Texture = description.hasTexture &&
-                description.hasAlpha8Texture && noShader;
-        const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
-                description.hasGradient && !description.hasBitmap &&
-                description.gradientType == ProgramDescription::kGradientLinear;
-
-        if (singleColor) {
-            shader.append(gFS_Fast_SingleColor);
-            fast = true;
-        } else if (singleTexture) {
-            if (!description.modulate) {
-                shader.append(gFS_Fast_SingleTexture);
-            } else {
-                shader.append(gFS_Fast_SingleModulateTexture);
-            }
-            fast = true;
-        } else if (singleA8Texture) {
-            if (!description.modulate) {
-                if (description.hasGammaCorrection) {
-                    shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
-                } else {
-                    shader.append(gFS_Fast_SingleA8Texture);
-                }
-            } else {
-                if (description.hasGammaCorrection) {
-                    shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
-                } else {
-                    shader.append(gFS_Fast_SingleModulateA8Texture);
-                }
-            }
-            fast = true;
-        } else if (singleGradient) {
-            shader.append(gFS_Gradient_Functions);
-            shader.append(gFS_Gradient_Preamble[mHasSRGB]);
-            if (!description.modulate) {
-                shader.append(gFS_Fast_SingleGradient[description.isSimpleGradient]);
-            } else {
-                shader.append(gFS_Fast_SingleModulateGradient[description.isSimpleGradient]);
-            }
-            fast = true;
-        }
-
-        if (fast) {
-#if DEBUG_PROGRAMS
-                PROGRAM_LOGD("*** Fast case:\n");
-                PROGRAM_LOGD("*** Generated fragment shader:\n\n");
-                printLongString(shader);
-#endif
-
-            return shader;
-        }
-    }
-
     if (description.hasBitmap) {
         if (description.isShaderBitmapExternal) {
             shader.append(gFS_Uniforms_BitmapExternalSampler);
@@ -719,6 +637,13 @@
     if (description.useShaderBasedWrap) {
         generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
     }
+    if (description.hasGradient || description.hasLinearTexture) {
+        shader.append(gFS_Transfer_Functions);
+    }
+    if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
+            !description.hasAlpha8Texture)) {
+        shader.append(gFS_OETF[description.hasLinearTexture && !mHasSRGB]);
+    }
     if (description.hasGradient) {
         shader.append(gFS_Gradient_Functions);
         shader.append(gFS_Gradient_Preamble[mHasSRGB]);
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 705395e..50af9c8 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -44,10 +44,14 @@
     case GL_RGBA16F:
         return 8;
     default:
-        LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat);
+        LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat);
     }
 }
 
+bool Texture::isLinear() const {
+    return mInternalFormat == GL_RGBA16F;
+}
+
 void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force) {
 
     if (force || wrapS != mWrapS || wrapT != mWrapT) {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index b8397cc..ce9d4dc 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -128,6 +128,11 @@
     }
 
     /**
+     * Returns true if this texture uses a linear encoding format.
+     */
+    bool isLinear() const;
+
+    /**
      * Generation of the backing bitmap,
      */
     uint32_t generation = 0;
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index 37126a6..f69da48 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -29,5 +29,5 @@
     libandroidfw
 
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
-    LOCAL_SHARED_LIBRARIES += libRS libRScpp
+    LOCAL_SHARED_LIBRARIES += libRScpp
 endif
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index d05e7f6..2ead5c5 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -24,6 +24,7 @@
 #include <SkGaussianEdgeShader.h>
 #include <SkPathOps.h>
 #include <SkRRectsGaussianEdgeMaskFilter.h>
+#include <SkShadowUtils.h>
 
 namespace android {
 namespace uirenderer {
@@ -115,498 +116,6 @@
     }
 }
 
-/**
- * @param canvas             the destination for the shadow draws
- * @param shape              the shape casting the shadow
- * @param casterZValue       the Z value of the caster RRect
- * @param ambientAlpha       the maximum alpha value to use when drawing the ambient shadow
- * @param draw               the function used to draw 'shape'
- */
-template <typename Shape, typename F>
-static void DrawAmbientShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue,
-        float ambientAlpha, F&& draw) {
-    if (ambientAlpha <= 0) {
-        return;
-    }
-
-    const float kHeightFactor = 1.f/128.f;
-    const float kGeomFactor = 64;
-
-    float umbraAlpha = 1 / (1 + SkMaxScalar(casterZValue*kHeightFactor, 0));
-    float radius = casterZValue*kHeightFactor*kGeomFactor;
-
-    sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
-            SkBlurMask::ConvertRadiusToSigma(radius), SkBlurMaskFilter::kNone_BlurFlag);
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    paint.setMaskFilter(std::move(mf));
-    paint.setARGB(ambientAlpha*umbraAlpha, 0, 0, 0);
-
-    draw(shape, paint);
-}
-
-/**
- * @param canvas             the destination for the shadow draws
- * @param shape              the shape casting the shadow
- * @param casterZValue       the Z value of the caster RRect
- * @param lightPos           the position of the light casting the shadow
- * @param lightWidth
- * @param spotAlpha          the maximum alpha value to use when drawing the spot shadow
- * @param draw               the function used to draw 'shape'
- */
-template <typename Shape, typename F>
-static void DrawSpotShadowGeneral(SkCanvas* canvas, const Shape& shape, float casterZValue,
-        float spotAlpha, F&& draw) {
-    if (spotAlpha <= 0) {
-        return;
-    }
-
-    const Vector3 lightPos = SkiaPipeline::getLightCenter();
-    float zRatio = casterZValue / (lightPos.z - casterZValue);
-    // clamp
-    if (zRatio < 0.0f) {
-        zRatio = 0.0f;
-    } else if (zRatio > 0.95f) {
-        zRatio = 0.95f;
-    }
-
-    float blurRadius = SkiaPipeline::getLightRadius()*zRatio;
-
-    SkAutoCanvasRestore acr(canvas, true);
-
-    sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
-            SkBlurMask::ConvertRadiusToSigma(blurRadius), SkBlurMaskFilter::kNone_BlurFlag);
-
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    paint.setMaskFilter(std::move(mf));
-    paint.setARGB(spotAlpha, 0, 0, 0);
-
-    // approximate projection by translating and scaling projected offset of bounds center
-    // TODO: compute the actual 2D projection
-    SkScalar scale = lightPos.z / (lightPos.z - casterZValue);
-    canvas->scale(scale, scale);
-    SkPoint center = SkPoint::Make(shape.getBounds().centerX(), shape.getBounds().centerY());
-    SkMatrix ctmInverse;
-    if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
-        ALOGW("Matrix is degenerate. Will not render shadow!");
-        return;
-    }
-    SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y);
-    ctmInverse.mapPoints(&lightPos2D, 1);
-    canvas->translate(zRatio*(center.fX - lightPos2D.fX), zRatio*(center.fY - lightPos2D.fY));
-
-    draw(shape, paint);
-}
-
-#define MAX_BLUR_RADIUS 16383.75f
-#define MAX_PAD         64
-
-/**
- * @param casterRect         the rectangle bounds of the RRect casting the shadow
- * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow
- * @param ambientAlpha       the maximum alpha value to use when drawing the ambient shadow
- * @param spotAlpha          the maximum alpha value to use when drawing the spot shadow
- * @param casterAlpha        the alpha value of the RRect casting the shadow (0.0-1.0 range)
- * @param casterZValue       the Z value of the caster RRect
- * @param scaleFactor        the scale needed to map from src-space to device-space
- * @param canvas             the destination for the shadow draws
- */
-static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius,
-        SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue,
-        SkScalar scaleFactor, SkCanvas* canvas) {
-    SkASSERT(casterCornerRadius >= 0.0f);
-
-    // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
-    const SkScalar minRadius = 0.5f / scaleFactor;
-
-    const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()),
-            SkScalarHalf(casterRect.height()));
-    const bool isRect = casterCornerRadius <= minRadius;
-
-    sk_sp<SkShader> edgeShader(SkGaussianEdgeShader::Make());
-
-    if (ambientAlpha > 0.0f) {
-        static const float kHeightFactor = 1.0f / 128.0f;
-        static const float kGeomFactor = 64.0f;
-
-        SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor;
-        // the device-space radius sent to the blur shader must fit in 14.2 fixed point
-        if (srcSpaceAmbientRadius*scaleFactor > MAX_BLUR_RADIUS) {
-            srcSpaceAmbientRadius = MAX_BLUR_RADIUS/scaleFactor;
-        }
-        const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f));
-        const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha;
-
-        // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius
-        // to get our stroke shape.
-        SkScalar ambientPathOutset = std::max(ambientOffset - srcSpaceAmbientRadius * 0.5f,
-                minRadius);
-
-        SkRRect ambientRRect;
-        const SkRect temp = casterRect.makeOutset(ambientPathOutset, ambientPathOutset);
-        if (isOval) {
-            ambientRRect = SkRRect::MakeOval(temp);
-        } else if (isRect) {
-            ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset);
-        } else {
-            ambientRRect = SkRRect::MakeRectXY(temp, casterCornerRadius + ambientPathOutset,
-                    casterCornerRadius + ambientPathOutset);
-        }
-
-        SkPaint paint;
-        paint.setAntiAlias(true);
-        paint.setStyle(SkPaint::kStroke_Style);
-        // we outset the stroke a little to cover up AA on the interior edge
-        float pad = 0.5f;
-        paint.setStrokeWidth(srcSpaceAmbientRadius + 2.0f * pad);
-        // handle scale of radius and pad due to CTM
-        pad *= scaleFactor;
-        const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
-        SkASSERT(devSpaceAmbientRadius <= MAX_BLUR_RADIUS);
-        SkASSERT(pad < MAX_PAD);
-        // convert devSpaceAmbientRadius to 14.2 fixed point and place in the R & G components
-        // convert pad to 6.2 fixed point and place in the B component
-        uint16_t iDevSpaceAmbientRadius = (uint16_t)(4.0f * devSpaceAmbientRadius);
-        paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, iDevSpaceAmbientRadius >> 8,
-                iDevSpaceAmbientRadius & 0xff, (unsigned char)(4.0f * pad)));
-
-        paint.setShader(edgeShader);
-        canvas->drawRRect(ambientRRect, paint);
-    }
-
-    if (spotAlpha > 0.0f) {
-        const Vector3 lightPos = SkiaPipeline::getLightCenter();
-        float zRatio = casterZValue / (lightPos.z - casterZValue);
-        // clamp
-        if (zRatio < 0.0f) {
-            zRatio = 0.0f;
-        } else if (zRatio > 0.95f) {
-            zRatio = 0.95f;
-        }
-
-        const SkScalar lightWidth = SkiaPipeline::getLightRadius();
-        SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio;
-        // the device-space radius sent to the blur shader must fit in 14.2 fixed point
-        if (srcSpaceSpotRadius*scaleFactor > MAX_BLUR_RADIUS) {
-            srcSpaceSpotRadius = MAX_BLUR_RADIUS/scaleFactor;
-        }
-
-        SkRRect spotRRect;
-        if (isOval) {
-            spotRRect = SkRRect::MakeOval(casterRect);
-        } else if (isRect) {
-            spotRRect = SkRRect::MakeRectXY(casterRect, minRadius, minRadius);
-        } else {
-            spotRRect = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius);
-        }
-
-        SkRRect spotShadowRRect;
-        // Compute the scale and translation for the spot shadow.
-        const SkScalar scale = lightPos.z / (lightPos.z - casterZValue);
-        spotRRect.transform(SkMatrix::MakeScale(scale, scale), &spotShadowRRect);
-
-        SkPoint center = SkPoint::Make(spotShadowRRect.rect().centerX(),
-                                       spotShadowRRect.rect().centerY());
-        SkMatrix ctmInverse;
-        if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
-            ALOGW("Matrix is degenerate. Will not render spot shadow!");
-            return;
-        }
-        SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y);
-        ctmInverse.mapPoints(&lightPos2D, 1);
-        const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
-                zRatio*(center.fY - lightPos2D.fY));
-
-        SkAutoCanvasRestore acr(canvas, true);
-
-        // We want to extend the stroked area in so that it meets up with the caster
-        // geometry. The stroked geometry will, by definition already be inset half the
-        // stroke width but we also have to account for the scaling.
-        // We also add 1/2 to cover up AA on the interior edge.
-        SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(casterRect.fLeft),
-                SkTAbs(casterRect.fRight)), SkTMax(SkTAbs(casterRect.fTop),
-                SkTAbs(casterRect.fBottom)));
-        SkScalar insetAmount = spotOffset.length() - (0.5f * srcSpaceSpotRadius) +
-                scaleOffset + 0.5f;
-
-        // Compute area
-        SkScalar strokeWidth = srcSpaceSpotRadius + insetAmount;
-        SkScalar strokedArea = 2.0f*strokeWidth * (spotShadowRRect.width()
-                + spotShadowRRect.height());
-        SkScalar filledArea = (spotShadowRRect.height() + srcSpaceSpotRadius)
-                * (spotShadowRRect.width() + srcSpaceSpotRadius);
-
-        SkPaint paint;
-        paint.setAntiAlias(true);
-
-        // If the area of the stroked geometry is larger than the fill geometry, just fill it.
-        if (strokedArea > filledArea || casterAlpha < 1.0f || insetAmount < 0.0f) {
-            paint.setStyle(SkPaint::kStrokeAndFill_Style);
-            paint.setStrokeWidth(srcSpaceSpotRadius);
-        } else {
-            // Since we can't have unequal strokes, inset the shadow rect so the inner
-            // and outer edges of the stroke will land where we want.
-            SkRect insetRect = spotShadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
-            SkScalar insetRad = SkTMax(spotShadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
-                    minRadius);
-            spotShadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
-            paint.setStyle(SkPaint::kStroke_Style);
-            paint.setStrokeWidth(strokeWidth);
-        }
-
-        // handle scale of radius and pad due to CTM
-        const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor;
-        SkASSERT(devSpaceSpotRadius <= MAX_BLUR_RADIUS);
-
-        const SkScalar devSpaceSpotPad = 0;
-        SkASSERT(devSpaceSpotPad < MAX_PAD);
-
-        // convert devSpaceSpotRadius to 14.2 fixed point and place in the R & G
-        // components convert devSpaceSpotPad to 6.2 fixed point and place in the B component
-        uint16_t iDevSpaceSpotRadius = (uint16_t)(4.0f * devSpaceSpotRadius);
-        paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, iDevSpaceSpotRadius >> 8,
-                iDevSpaceSpotRadius & 0xff, (unsigned char)(4.0f * devSpaceSpotPad)));
-        paint.setShader(edgeShader);
-
-        canvas->translate(spotOffset.fX, spotOffset.fY);
-        canvas->drawRRect(spotShadowRRect, paint);
-    }
-}
-
-/**
- * @param casterRect         the rectangle bounds of the RRect casting the shadow
- * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow
- * @param ambientAlpha       the maximum alpha value to use when drawing the ambient shadow
- * @param spotAlpha          the maximum alpha value to use when drawing the spot shadow
- * @param casterZValue       the Z value of the caster RRect
- * @param scaleFactor        the scale needed to map from src-space to device-space
- * @param clipRR             the oval or rect with which the drawn roundrect must be intersected
- * @param canvas             the destination for the shadow draws
- */
-static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius,
-        SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor,
-        const SkRRect& clipRR, SkCanvas* canvas) {
-    SkASSERT(casterCornerRadius >= 0.0f);
-
-    const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()),
-            SkScalarHalf(casterRect.height()));
-
-    if (ambientAlpha > 0.0f) {
-        static const float kHeightFactor = 1.0f / 128.0f;
-        static const float kGeomFactor = 64.0f;
-
-        const SkScalar srcSpaceAmbientRadius = casterZValue * kHeightFactor * kGeomFactor;
-        const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
-
-        const float umbraAlpha = 1.0f / (1.0f + std::max(casterZValue * kHeightFactor, 0.0f));
-        const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha;
-
-        const SkRect srcSpaceAmbientRect = casterRect.makeOutset(ambientOffset, ambientOffset);
-        SkRect devSpaceAmbientRect;
-        canvas->getTotalMatrix().mapRect(&devSpaceAmbientRect, srcSpaceAmbientRect);
-
-        SkRRect devSpaceAmbientRRect;
-        if (isOval) {
-            devSpaceAmbientRRect = SkRRect::MakeOval(devSpaceAmbientRect);
-        } else {
-            const SkScalar devSpaceCornerRadius = scaleFactor * (casterCornerRadius + ambientOffset);
-            devSpaceAmbientRRect = SkRRect::MakeRectXY(devSpaceAmbientRect, devSpaceCornerRadius,
-                    devSpaceCornerRadius);
-        }
-
-        const SkRect srcSpaceAmbClipRect = clipRR.rect().makeOutset(ambientOffset, ambientOffset);
-        SkRect devSpaceAmbClipRect;
-        canvas->getTotalMatrix().mapRect(&devSpaceAmbClipRect, srcSpaceAmbClipRect);
-        SkRRect devSpaceAmbientClipRR;
-        if (clipRR.isOval()) {
-            devSpaceAmbientClipRR = SkRRect::MakeOval(devSpaceAmbClipRect);
-        } else {
-            SkASSERT(clipRR.isRect());
-            devSpaceAmbientClipRR = SkRRect::MakeRect(devSpaceAmbClipRect);
-        }
-
-        SkRect cover = srcSpaceAmbClipRect;
-        if (!cover.intersect(srcSpaceAmbientRect)) {
-            return;
-        }
-
-        SkPaint paint;
-        paint.setColor(SkColorSetARGB((unsigned char) ambientAlpha, 0, 0, 0));
-        paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceAmbientRRect,
-            devSpaceAmbientClipRR, devSpaceAmbientRadius));
-        canvas->drawRect(cover, paint);
-    }
-
-    if (spotAlpha > 0.0f) {
-        const Vector3 lightPos = SkiaPipeline::getLightCenter();
-        float zRatio = casterZValue / (lightPos.z - casterZValue);
-        // clamp
-        if (zRatio < 0.0f) {
-            zRatio = 0.0f;
-        } else if (zRatio > 0.95f) {
-            zRatio = 0.95f;
-        }
-
-        const SkScalar lightWidth = SkiaPipeline::getLightRadius();
-        const SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio;
-        const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor;
-
-        // Compute the scale and translation for the spot shadow.
-        const SkScalar scale = lightPos.z / (lightPos.z - casterZValue);
-        const SkMatrix spotMatrix = SkMatrix::MakeScale(scale, scale);
-
-        SkRect srcSpaceScaledRect = casterRect;
-        spotMatrix.mapRect(&srcSpaceScaledRect);
-        srcSpaceScaledRect.outset(SkScalarHalf(srcSpaceSpotRadius),
-                SkScalarHalf(srcSpaceSpotRadius));
-
-        SkRRect srcSpaceSpotRRect;
-        if (isOval) {
-            srcSpaceSpotRRect = SkRRect::MakeOval(srcSpaceScaledRect);
-        } else {
-            srcSpaceSpotRRect = SkRRect::MakeRectXY(srcSpaceScaledRect, casterCornerRadius * scale,
-                    casterCornerRadius * scale);
-        }
-
-        SkPoint center = SkPoint::Make(srcSpaceSpotRRect.rect().centerX(),
-                srcSpaceSpotRRect.rect().centerY());
-        SkMatrix ctmInverse;
-        if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
-            ALOGW("Matrix is degenerate. Will not render spot shadow!");
-            return;
-        }
-        SkPoint lightPos2D = SkPoint::Make(lightPos.x, lightPos.y);
-        ctmInverse.mapPoints(&lightPos2D, 1);
-        const SkPoint spotOffset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
-                zRatio*(center.fY - lightPos2D.fY));
-
-        SkAutoCanvasRestore acr(canvas, true);
-        canvas->translate(spotOffset.fX, spotOffset.fY);
-
-        SkRect devSpaceScaledRect;
-        canvas->getTotalMatrix().mapRect(&devSpaceScaledRect, srcSpaceScaledRect);
-
-        SkRRect devSpaceSpotRRect;
-        if (isOval) {
-            devSpaceSpotRRect = SkRRect::MakeOval(devSpaceScaledRect);
-        } else {
-            const SkScalar devSpaceScaledCornerRadius = casterCornerRadius * scale * scaleFactor;
-            devSpaceSpotRRect = SkRRect::MakeRectXY(devSpaceScaledRect, devSpaceScaledCornerRadius,
-                    devSpaceScaledCornerRadius);
-        }
-
-        SkPaint paint;
-        paint.setColor(SkColorSetARGB((unsigned char) spotAlpha, 0, 0, 0));
-
-        SkRect srcSpaceScaledClipRect = clipRR.rect();
-        spotMatrix.mapRect(&srcSpaceScaledClipRect);
-        srcSpaceScaledClipRect.outset(SkScalarHalf(srcSpaceSpotRadius),
-                SkScalarHalf(srcSpaceSpotRadius));
-
-        SkRect devSpaceScaledClipRect;
-        canvas->getTotalMatrix().mapRect(&devSpaceScaledClipRect, srcSpaceScaledClipRect);
-        SkRRect devSpaceSpotClipRR;
-        if (clipRR.isOval()) {
-            devSpaceSpotClipRR = SkRRect::MakeOval(devSpaceScaledClipRect);
-        } else {
-            SkASSERT(clipRR.isRect());
-            devSpaceSpotClipRR = SkRRect::MakeRect(devSpaceScaledClipRect);
-        }
-
-        paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceSpotRRect,
-            devSpaceSpotClipRR, devSpaceSpotRadius));
-
-        SkRect cover = srcSpaceScaledClipRect;
-        if (!cover.intersect(srcSpaceSpotRRect.rect())) {
-            return;
-        }
-
-        canvas->drawRect(cover, paint);
-    }
-}
-
-/**
- * @param casterRect         the rectangle bounds of the RRect casting the shadow
- * @param casterCornerRadius the x&y radius for all the corners of the RRect casting the shadow
- * @param casterClipRect     a rectangular clip that must be intersected with the
- *                           shadow-casting RRect prior to casting the shadow
- * @param revealClip         a circular clip that must be interested with the castClipRect
- *                           and the shadow-casting rect prior to casting the shadow
- * @param ambientAlpha       the maximum alpha value to use when drawing the ambient shadow
- * @param spotAlpha          the maximum alpha value to use when drawing the spot shadow
- * @param casterAlpha        the alpha value of the RRect casting the shadow (0.0-1.0 range)
- * @param casterZValue       the Z value of the caster RRect
- * @param canvas             the destination for the shadow draws
- *
- * We have special cases for 4 round rect shadow draws:
- *    1) a RRect clipped by a reveal animation
- *    2) a RRect clipped by a rectangle
- *    3) an unclipped RRect with non-uniform scale
- *    4) an unclipped RRect with uniform scale
- * 1,2 and 4 require that the scale is uniform.
- * 1 and 2 require that rects stay rects.
- */
-static bool DrawShadowsAsRRects(const SkRect& casterRect, SkScalar casterCornerRadius,
-        const SkRect& casterClipRect, const RevealClip& revealClip, SkScalar ambientAlpha,
-        SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkCanvas* canvas) {
-    SkScalar scaleFactors[2];
-    if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
-        ALOGW("Matrix is degenerate. Will not render shadow!");
-        return false;
-    }
-
-    // The casterClipRect will be empty when bounds clipping is disabled
-    bool casterIsClippedByRect = !casterClipRect.isEmpty();
-    bool uniformScale = scaleFactors[0] == scaleFactors[1];
-
-    if (revealClip.willClip()) {
-        if (casterIsClippedByRect || !uniformScale || !canvas->getTotalMatrix().rectStaysRect()) {
-            return false;  // Fall back to the slow path since PathOps are required
-        }
-
-        const float revealRadius = revealClip.getRadius();
-        SkRect revealClipRect = SkRect::MakeLTRB(revealClip.getX()-revealRadius,
-                revealClip.getY()-revealRadius, revealClip.getX()+revealRadius,
-                revealClip.getY()+revealRadius);
-        SkRRect revealClipRR = SkRRect::MakeOval(revealClipRect);
-
-        DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha,
-                casterZValue, scaleFactors[0], revealClipRR, canvas);
-        return true;
-    }
-
-    if (casterIsClippedByRect) {
-        if (!uniformScale || !canvas->getTotalMatrix().rectStaysRect()) {
-            return false;  // Fall back to the slow path since PathOps are required
-        }
-
-        SkRRect casterClipRR = SkRRect::MakeRect(casterClipRect);
-
-        DrawRRectShadowsWithClip(casterRect, casterCornerRadius, ambientAlpha, spotAlpha,
-                casterZValue, scaleFactors[0], casterClipRR, canvas);
-        return true;
-    }
-
-    // The fast path needs uniform scale
-    if (!uniformScale) {
-        SkRRect casterRR = SkRRect::MakeRectXY(casterRect, casterCornerRadius, casterCornerRadius);
-        DrawAmbientShadowGeneral(canvas, casterRR, casterZValue, ambientAlpha,
-                [&](const SkRRect& rrect, const SkPaint& paint) {
-                    canvas->drawRRect(rrect, paint);
-                });
-        DrawSpotShadowGeneral(canvas, casterRR, casterZValue, spotAlpha,
-                [&](const SkRRect& rrect, const SkPaint& paint) {
-                canvas->drawRRect(rrect, paint);
-                });
-        return true;
-    }
-
-    DrawRRectShadows(casterRect, casterCornerRadius, ambientAlpha, spotAlpha, casterAlpha,
-            casterZValue, scaleFactors[0], canvas);
-    return true;
-}
-
 // copied from FrameBuilder::deferShadow
 void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) {
     const RenderProperties& casterProperties = caster->getNodeProperties();
@@ -626,8 +135,8 @@
         return;
     }
 
-    float ambientAlpha = SkiaPipeline::getAmbientShadowAlpha()*casterAlpha;
-    float spotAlpha = SkiaPipeline::getSpotShadowAlpha()*casterAlpha;
+    float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha;
+    float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha;
     const float casterZValue = casterProperties.getZ();
 
     const RevealClip& revealClip = casterProperties.getRevealClip();
@@ -659,19 +168,7 @@
     hwuiMatrix.copyTo(shadowMatrix);
     canvas->concat(shadowMatrix);
 
-    const Outline& casterOutline = casterProperties.getOutline();
-    Rect possibleRect;
-    float radius;
-    if (casterOutline.getAsRoundRect(&possibleRect, &radius)) {
-        if (DrawShadowsAsRRects(possibleRect.toSkRect(), radius, casterClipRect, revealClip,
-                ambientAlpha, spotAlpha, casterAlpha, casterZValue, canvas)) {
-            return;
-        }
-    }
-
-    // Hard cases and calls to general shadow code
     const SkPath* casterOutlinePath = casterProperties.getOutline().getPath();
-
     // holds temporary SkPath to store the result of intersections
     SkPath tmpPath;
     const SkPath* casterPath = casterOutlinePath;
@@ -691,16 +188,11 @@
         Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath);
         casterPath = &tmpPath;
     }
-
-    DrawAmbientShadowGeneral(canvas, *casterPath, casterZValue, ambientAlpha,
-            [&](const SkPath& path, const SkPaint& paint) {
-                canvas->drawPath(path, paint);
-            });
-
-    DrawSpotShadowGeneral(canvas, *casterPath, casterZValue, spotAlpha,
-            [&](const SkPath& path, const SkPaint& paint) {
-                canvas->drawPath(path, paint);
-            });
+    const Vector3 lightPos = SkiaPipeline::getLightCenter();
+    SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z);
+    SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos,
+            SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
+            casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
 }
 
 }; // namespace skiapipeline
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 0d567f7..7dfc2ee 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -80,6 +80,7 @@
     delete mStencil;
     mStencil = nullptr;
 
+    destroyLayersInUpdater();
     GpuMemoryTracker::onGpuContextDestroyed();
 }
 
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index a44fa9d..f78bf7a 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -99,8 +99,6 @@
         mActiveLayerUpdaters.erase(layerUpdater);
     }
 
-    void destroyLayersInUpdater();
-
     // TODO: This system is a little clunky feeling, this could use some
     // more thinking...
     void postDecStrong(VirtualLightRefBase* object);
@@ -121,6 +119,7 @@
 private:
     void interruptForFunctorInvoke();
     void resumeFromFunctorInvoke();
+    void destroyLayersInUpdater();
 
     explicit RenderState(renderthread::RenderThread& thread);
     ~RenderState();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5a7de1d..a53e5e0 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -570,7 +570,6 @@
         }
         mRenderPipeline->onDestroyHardwareResources();
     }
-    mRenderThread.renderState().destroyLayersInUpdater();
 }
 
 void CanvasContext::trimMemory(RenderThread& thread, int level) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index fb79272..11614fa 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -667,11 +667,17 @@
 }
 
 int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
-    SETUP_TASK(copyGraphicBufferInto);
-    args->thread = &RenderThread::getInstance();
-    args->bitmap = bitmap;
-    args->buffer = buffer;
-    return static_cast<int>(reinterpret_cast<intptr_t>(staticPostAndWait(task)));
+    RenderThread& thread = RenderThread::getInstance();
+    if (Properties::isSkiaEnabled() && gettid() == thread.getTid()) {
+        //TODO: fix everything that hits this. We should never be triggering a readback ourselves.
+        return (int) thread.readback().copyGraphicBufferInto(buffer, bitmap);
+    } else {
+        SETUP_TASK(copyGraphicBufferInto);
+        args->thread = &thread;
+        args->bitmap = bitmap;
+        args->buffer = buffer;
+        return static_cast<int>(reinterpret_cast<intptr_t>(staticPostAndWait(task)));
+    }
 }
 
 void RenderProxy::post(RenderTask* task) {
@@ -690,6 +696,7 @@
 
 void* RenderProxy::staticPostAndWait(MethodInvokeRenderTask* task) {
     RenderThread& thread = RenderThread::getInstance();
+    LOG_ALWAYS_FATAL_IF(gettid() == thread.getTid());
     void* retval;
     task->setReturnPtr(&retval);
     thread.queueAndWait(task);
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 454ce4d..c2c2f22 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -603,6 +603,11 @@
 }
 
 void VulkanManager::swapBuffers(VulkanSurface* surface) {
+    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+        ATRACE_NAME("Finishing GPU work");
+        mDeviceWaitIdle(mBackendContext->fDevice);
+    }
+
     VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
             surface->mCurrentBackbufferIndex;
     GrVkImageInfo* imageInfo;
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 5e937f3..c1ca1e7 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -16,6 +16,8 @@
 
 #include "tests/common/TestContext.h"
 
+#include <cutils/trace.h>
+
 namespace android {
 namespace uirenderer {
 namespace test {
@@ -98,6 +100,11 @@
 }
 
 void TestContext::waitForVsync() {
+    // Hacky fix for not getting sysprop change callbacks
+    // We just poll the sysprop in vsync since it's when the UI thread is
+    // "idle" and shouldn't burn too much time
+    atrace_update_tags();
+
     if (mConsumer.get()) {
         BufferItem buffer;
         if (mConsumer->acquireBuffer(&buffer, 0, false) == OK) {
diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
new file mode 100644
index 0000000..fac3968
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+
+class ShadowShaderAnimation;
+
+static TestScene::Registrar _ShadowShader(TestScene::Info{
+    "shadowshader",
+    "A set of overlapping shadowed areas with simple tessellation useful for"
+    " benchmarking shadow shader performance.",
+    TestScene::simpleCreateScene<ShadowShaderAnimation>
+});
+
+class ShadowShaderAnimation : public TestScene {
+public:
+    std::vector< sp<RenderNode> > cards;
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
+        canvas.insertReorderBarrier(true);
+
+        int outset = 50;
+        for (int i = 0; i < 10; i++) {
+            sp<RenderNode> card = createCard(outset, outset,
+                    width - (outset * 2), height - (outset * 2));
+            canvas.drawRenderNode(card.get());
+            cards.push_back(card);
+        }
+
+        canvas.insertReorderBarrier(false);
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 10;
+        for (size_t ci = 0; ci < cards.size(); ci++) {
+            cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
+            cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
+            cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        }
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        return TestUtils::createNode(x, y, x + width, y + height,
+                [width, height](RenderProperties& props, Canvas& canvas) {
+            props.setElevation(1000);
+
+            // Set 0 radius, no clipping, so shadow is easy to compute. Slightly transparent outline
+            // to signal contents aren't opaque (not necessary though, as elevation is so high, no
+            // inner content to cut out)
+            props.mutableOutline().setRoundRect(0, 0, width, height, 0, 0.99f);
+            props.mutableOutline().setShouldClip(false);
+
+            // don't draw anything to card's canvas - we just want the shadow
+        });
+    }
+};
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
new file mode 100644
index 0000000..a63a585
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+
+#include <SkColorMatrixFilter.h>
+#include <SkGradientShader.h>
+
+class SimpleColorMatrixAnimation;
+
+static TestScene::Registrar _SimpleColorMatrix(TestScene::Info{
+    "simpleColorMatrix",
+    "A color matrix shader benchmark for the simple scale/translate case, which has R, G, and B "
+    "all scaled and translated the same amount.",
+    TestScene::simpleCreateScene<SimpleColorMatrixAnimation>
+});
+
+class SimpleColorMatrixAnimation : public TestScene {
+public:
+    std::vector< sp<RenderNode> > cards;
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+
+        sp<RenderNode> card = createCard(0, 0, width, height);
+        canvas.drawRenderNode(card.get());
+        cards.push_back(card);
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 20;
+        for (size_t ci = 0; ci < cards.size(); ci++) {
+            cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
+            cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
+            cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        }
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        return TestUtils::createNode(x, y, x + width, y + height,
+                [width, height](RenderProperties& props, Canvas& canvas) {
+            SkPaint paint;
+            float matrix[20] = { 0 };
+
+            // Simple scale/translate case where R, G, and B are all treated equivalently
+            matrix[SkColorMatrix::kR_Scale] = 1.1f;
+            matrix[SkColorMatrix::kG_Scale] = 1.1f;
+            matrix[SkColorMatrix::kB_Scale] = 1.1f;
+            matrix[SkColorMatrix::kA_Scale] = 0.5f;
+
+            matrix[SkColorMatrix::kR_Trans] = 5.0f;
+            matrix[SkColorMatrix::kG_Trans] = 5.0f;
+            matrix[SkColorMatrix::kB_Trans] = 5.0f;
+            matrix[SkColorMatrix::kA_Trans] = 10.0f;
+
+            paint.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
+
+            // set a shader so it's not likely for the matrix to be optimized away (since a clever
+            // enough renderer might apply it directly to the paint color)
+            float pos[] = { 0, 1 };
+            SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
+            SkColor colors[2] = { Color::DeepPurple_500, Color::DeepOrange_500 };
+            paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
+                SkShader::kClamp_TileMode));
+
+            // overdraw several times to emphasize shader cost
+            for (int i = 0; i < 10; i++) {
+                canvas.drawRect(i, i, width, height, paint);
+            }
+        });
+    }
+};
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
new file mode 100644
index 0000000..053eb6d
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+
+#include "TestSceneBase.h"
+
+#include <SkGradientShader.h>
+
+class SimpleGradientAnimation;
+
+static TestScene::Registrar _SimpleGradient(TestScene::Info{
+    "simpleGradient",
+    "A benchmark of shader performance of linear, 2 color gradients with black in them.",
+    TestScene::simpleCreateScene<SimpleGradientAnimation>
+});
+
+class SimpleGradientAnimation : public TestScene {
+public:
+    std::vector< sp<RenderNode> > cards;
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+
+        sp<RenderNode> card = createCard(0, 0, width, height);
+        canvas.drawRenderNode(card.get());
+        cards.push_back(card);
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 20;
+        for (size_t ci = 0; ci < cards.size(); ci++) {
+            cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
+            cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
+            cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        }
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        return TestUtils::createNode(x, y, x + width, y + height,
+                [width, height](RenderProperties& props, Canvas& canvas) {
+            float pos[] = { 0, 1 };
+            SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
+            SkPaint paint;
+            // overdraw several times to emphasize shader cost
+            for (int i = 0; i < 10; i++) {
+                // use i%2 start position to pick 2 color combo with black in it
+                SkColor colors[3] = { Color::Transparent, Color::Black, Color::Cyan_500 };
+                paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
+                    SkShader::kClamp_TileMode));
+                canvas.drawRect(i, i, width, height, paint);
+            }
+        });
+    }
+};
diff --git a/location/java/android/location/BatchedLocationCallback.java b/location/java/android/location/BatchedLocationCallback.java
new file mode 100644
index 0000000..f1c40ae
--- /dev/null
+++ b/location/java/android/location/BatchedLocationCallback.java
@@ -0,0 +1,44 @@
+/*
+ * 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 android.location;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Used for receiving notifications from the LocationManager when
+ * the a batch of location is ready. These methods are called if the
+ * BatchedLocationCallback has been registered with the location manager service
+ * using the
+ * {@link LocationManager#registerGnssBatchedLocationCallback#startGnssBatch(long,
+ * boolean, BatchedLocationCallback, android.os.Handler)} method.
+ * @hide
+ */
+@SystemApi
+public abstract class BatchedLocationCallback {
+
+    /**
+     * Called when a new batch of locations is ready
+     *
+     * @param locations A list of all new locations (possibly zero of them.)
+     */
+    public void onLocationBatch(List<Location> locations) {}
+}
diff --git a/location/java/android/location/BatchedLocationCallbackTransport.java b/location/java/android/location/BatchedLocationCallbackTransport.java
new file mode 100644
index 0000000..e00f855
--- /dev/null
+++ b/location/java/android/location/BatchedLocationCallbackTransport.java
@@ -0,0 +1,66 @@
+/*
+ * 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 android.location;
+
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * A handler class to manage transport callbacks for {@link BatchedLocationCallback}.
+ *
+ * @hide
+ */
+class BatchedLocationCallbackTransport
+        extends LocalListenerHelper<BatchedLocationCallback> {
+    private final ILocationManager mLocationManager;
+
+    private final IBatchedLocationCallback mCallbackTransport = new CallbackTransport();
+
+    public BatchedLocationCallbackTransport(Context context, ILocationManager locationManager) {
+        super(context, "BatchedLocationCallbackTransport");
+        mLocationManager = locationManager;
+    }
+
+    @Override
+    protected boolean registerWithServer() throws RemoteException {
+        return mLocationManager.addGnssBatchingCallback(
+                mCallbackTransport,
+                getContext().getPackageName());
+    }
+
+    @Override
+    protected void unregisterFromServer() throws RemoteException {
+        mLocationManager.removeGnssBatchingCallback();
+    }
+
+    private class CallbackTransport extends IBatchedLocationCallback.Stub {
+        @Override
+        public void onLocationBatch(final List<Location> locations) {
+            ListenerOperation<BatchedLocationCallback> operation =
+                    new ListenerOperation<BatchedLocationCallback>() {
+                @Override
+                public void execute(BatchedLocationCallback callback)
+                        throws RemoteException {
+                    callback.onLocationBatch(locations);
+                }
+            };
+            foreach(operation);
+        }
+    }
+}
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index aa26111..c7188aa 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -89,7 +89,7 @@
      */
     public static abstract class Callback {
         /**
-         * The status of GNSS measurements event.
+         * The status of GNSS Navigation Message event.
          * @hide
          */
         @Retention(RetentionPolicy.SOURCE)
diff --git a/location/java/android/location/IBatchedLocationCallback.aidl b/location/java/android/location/IBatchedLocationCallback.aidl
new file mode 100644
index 0000000..dce9f96
--- /dev/null
+++ b/location/java/android/location/IBatchedLocationCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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 android.location;
+
+import android.location.Location;
+
+import java.util.List;
+
+/**
+ * {@hide}
+ */
+oneway interface IBatchedLocationCallback
+{
+    void onLocationBatch(in List<Location> locations);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index bc8b026..fc31f32 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,6 +21,7 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
+import android.location.IBatchedLocationCallback;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssStatusListener;
 import android.location.IGnssNavigationMessageListener;
@@ -71,6 +72,13 @@
 
     int getGnssYearOfHardware();
 
+    int getGnssBatchSize(String packageName);
+    boolean addGnssBatchingCallback(in IBatchedLocationCallback callback, String packageName);
+    void removeGnssBatchingCallback();
+    boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName);
+    void flushGnssBatch(String packageName);
+    boolean stopGnssBatch();
+
     // --- deprecated ---
     List<String> getAllProviders();
     List<String> getProviders(in Criteria criteria, boolean enabledOnly);
@@ -99,6 +107,9 @@
     // it need not be shared with other providers.
     void reportLocation(in Location location, boolean passive);
 
+    // Used when a (initially Gnss) Location batch arrives
+    void reportLocationBatch(in List<Location> locations);
+
     // for reporting callback completion
     void locationCallbackFinished(ILocationListener listener);
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 4e14626..f9385c6 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.location.ProviderProperties;
 
+import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -59,13 +60,15 @@
  * return location results, but the update rate will be throttled and the exact
  * location will be obfuscated to a coarse level of accuracy.
  */
-public class LocationManager {
+public class LocationManager
+{
     private static final String TAG = "LocationManager";
 
     private final Context mContext;
     private final ILocationManager mService;
     private final GnssMeasurementCallbackTransport mGnssMeasurementCallbackTransport;
     private final GnssNavigationMessageCallbackTransport mGnssNavigationMessageCallbackTransport;
+    private final BatchedLocationCallbackTransport mBatchedLocationCallbackTransport;
     private final HashMap<GpsStatus.Listener, GnssStatusListenerTransport> mGpsStatusListeners =
             new HashMap<>();
     private final HashMap<GpsStatus.NmeaListener, GnssStatusListenerTransport> mGpsNmeaListeners =
@@ -321,9 +324,13 @@
     public LocationManager(Context context, ILocationManager service) {
         mService = service;
         mContext = context;
-        mGnssMeasurementCallbackTransport = new GnssMeasurementCallbackTransport(mContext, mService);
+        mGnssMeasurementCallbackTransport =
+                new GnssMeasurementCallbackTransport(mContext, mService);
         mGnssNavigationMessageCallbackTransport =
                 new GnssNavigationMessageCallbackTransport(mContext, mService);
+        mBatchedLocationCallbackTransport =
+                new BatchedLocationCallbackTransport(mContext, mService);
+
     }
 
     private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1878,7 +1885,8 @@
      * No-op method to keep backward-compatibility.
      * Don't use it. Use {@link #unregisterGnssNavigationMessageCallback} instead.
      * @hide
-     * @deprecated use {@link #unregisterGnssNavigationMessageCallback(GnssMeasurements.Callback)}
+     * @deprecated use
+     * {@link #unregisterGnssNavigationMessageCallback(GnssNavigationMessage.Callback)}
      * instead
      */
     @Deprecated
@@ -1960,6 +1968,96 @@
     }
 
     /**
+     * Returns the batch size (in number of Location objects) that are supported by the batching
+     * interface.
+     *
+     * @return Maximum number of location objects that can be returned
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    public int getGnssBatchSize() {
+        try {
+            return mService.getGnssBatchSize(mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Start hardware-batching of GNSS locations. This API is primarily used when the AP is
+     * asleep and the device can batch GNSS locations in the hardware.
+     *
+     * Note this is designed (as was the fused location interface before it) for a single user
+     * SystemApi - requests are not consolidated.  Care should be taken when the System switches
+     * users that may have different batching requests, to stop hardware batching for one user, and
+     * restart it for the next.
+     *
+     * @param periodNanos Time interval, in nanoseconds, that the GNSS locations are requested
+     *                    within the batch
+     * @param wakeOnFifoFull True if the hardware batching should flush the locations in a
+     *                       a callback to the listener, when it's internal buffer is full.  If
+     *                       set to false, the oldest location information is, instead,
+     *                       dropped when the buffer is full.
+     * @param callback The listener on which to return the batched locations
+     * @param handler The handler on which to process the callback
+     *
+     * @return True if batching was successfully started
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    public boolean registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull,
+                                  BatchedLocationCallback callback, Handler handler) {
+        mBatchedLocationCallbackTransport.add(callback, handler);
+
+        try {
+            return mService.startGnssBatch(periodNanos, wakeOnFifoFull, mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Flush the batched GNSS locations.
+     * All GNSS locations currently ready in the batch are returned via the callback sent in
+     * startGnssBatch(), and the buffer containing the batched locations is cleared.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    public void flushGnssBatch() {
+        try {
+            mService.flushGnssBatch(mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stop batching locations. This API is primarily used when the AP is
+     * asleep and the device can batch locations in the hardware.
+     *
+     * @param callback the specific callback class to remove from the transport layer
+     *
+     * @return True if batching was successfully started
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    public boolean unregisterGnssBatchedLocationCallback(BatchedLocationCallback callback) {
+
+        mBatchedLocationCallbackTransport.remove(callback);
+
+        try {
+            return mService.stopGnssBatch();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sends additional commands to a location provider.
      * Can be used to support provider specific extensions to the Location Manager API
      *
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 391a905..ce58a9c 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -913,13 +913,13 @@
         }
     }
     /**
-     * @hide
-     * CANDIDATE FOR PUBLIC (or at least SYSTEM) API
      * Returns the stream type matching the given attributes for volume control.
      * Use this method to derive the stream type needed to configure the volume
-     * control slider in an {@link Activity} with {@link Activity#setVolumeControlStream(int)}.
+     * control slider in an {@link android.app.Activity} with
+     * {@link android.app.Activity#setVolumeControlStream(int)}.
      * <BR>Do not use this method to set the stream type on an audio player object
-     * (e.g. {@link AudioTrack}, {@link MediaPlayer}), use <code>AudioAttributes</code> instead.
+     * (e.g. {@link AudioTrack}, {@link MediaPlayer}) as this is deprecated,
+     * use <code>AudioAttributes</code> instead.
      * @param aa non-null AudioAttributes.
      * @return a valid stream type for <code>Activity</code> or stream volume control that matches
      *     the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5c9f270..9083c16 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -27,6 +27,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityThread;
 import android.content.Context;
 import android.os.Handler;
@@ -538,6 +539,15 @@
             throw new IllegalArgumentException("Illegal null AudioFormat");
         }
 
+        // Check if we should enable deep buffer mode
+        if (shouldEnablePowerSaving(mAttributes, format, bufferSizeInBytes, mode)) {
+            mAttributes = new AudioAttributes.Builder(mAttributes)
+                .replaceFlags((mAttributes.getAllFlags()
+                        | AudioAttributes.FLAG_DEEP_BUFFER)
+                        & ~AudioAttributes.FLAG_LOW_LATENCY)
+                .build();
+        }
+
         // remember which looper is associated with the AudioTrack instantiation
         Looper looper;
         if ((looper = Looper.myLooper()) == null) {
@@ -861,7 +871,10 @@
                     .build();
                 break;
             case PERFORMANCE_MODE_NONE:
-                break;
+                if (!shouldEnablePowerSaving(mAttributes, mFormat, mBufferSizeInBytes, mMode)) {
+                    break; // do not enable deep buffer mode.
+                }
+                // permitted to fall through to enable deep buffer
             case PERFORMANCE_MODE_POWER_SAVING:
                 mAttributes = new AudioAttributes.Builder(mAttributes)
                 .replaceFlags((mAttributes.getAllFlags()
@@ -912,6 +925,56 @@
             AudioFormat.CHANNEL_OUT_SIDE_LEFT |
             AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
 
+    // Returns a boolean whether the attributes, format, bufferSizeInBytes, mode allow
+    // power saving to be automatically enabled for an AudioTrack. Returns false if
+    // power saving is already enabled in the attributes parameter.
+    private static boolean shouldEnablePowerSaving(
+            @Nullable AudioAttributes attributes, @Nullable AudioFormat format,
+            int bufferSizeInBytes, int mode) {
+        // If no attributes, OK
+        // otherwise check attributes for USAGE_MEDIA and CONTENT_UNKNOWN, MUSIC, or MOVIE.
+        if (attributes != null &&
+                (attributes.getAllFlags() != 0  // cannot have any special flags
+                || attributes.getUsage() != AudioAttributes.USAGE_MEDIA
+                || (attributes.getContentType() != AudioAttributes.CONTENT_TYPE_UNKNOWN
+                    && attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MUSIC
+                    && attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MOVIE))) {
+            return false;
+        }
+
+        // Format must be fully specified and be linear pcm
+        if (format == null
+                || format.getSampleRate() == AudioFormat.SAMPLE_RATE_UNSPECIFIED
+                || !AudioFormat.isEncodingLinearPcm(format.getEncoding())
+                || !AudioFormat.isValidEncoding(format.getEncoding())
+                || format.getChannelCount() < 1) {
+            return false;
+        }
+
+        // Mode must be streaming
+        if (mode != MODE_STREAM) {
+            return false;
+        }
+
+        // A buffer size of 0 is always compatible with deep buffer (when called from the Builder)
+        // but for app compatibility we only use deep buffer power saving for large buffer sizes.
+        if (bufferSizeInBytes != 0) {
+            final long BUFFER_TARGET_MODE_STREAM_MS = 100;
+            final int MILLIS_PER_SECOND = 1000;
+            final long bufferTargetSize =
+                    BUFFER_TARGET_MODE_STREAM_MS
+                    * format.getChannelCount()
+                    * format.getBytesPerSample(format.getEncoding())
+                    * format.getSampleRate()
+                    / MILLIS_PER_SECOND;
+            if (bufferSizeInBytes < bufferTargetSize) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     // Convenience method for the constructor's parameter checks.
     // This is where constructor IllegalArgumentException-s are thrown
     // postconditions:
@@ -1893,7 +1956,13 @@
                         e.printStackTrace();
                     }
                     baseSetStartDelayMs(0);
-                    startImpl();
+                    try {
+                        startImpl();
+                    } catch (IllegalStateException e) {
+                        // fail silently for a state exception when it is happening after
+                        // a delayed start, as the player state could have changed between the
+                        // call to start() and the execution of startImpl()
+                    }
                 }
             }.start();
         }
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 4d332a8..2ca36ea 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -26,6 +26,7 @@
 import android.media.MediaFormat;
 import android.media.MediaHTTPService;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.IBinder;
 
 import com.android.internal.util.Preconditions;
@@ -598,6 +599,16 @@
      */
     public native boolean hasCacheReachedEndOfStream();
 
+    /**
+     *  Returns Analytics/Metrics data about the current media container.
+     *
+     * @return the set of keys and values available for the media being
+     * handled by this instance of MediaExtractor
+     *
+     */
+    public native Bundle getMetrics();
+
+
     private static native final void native_init();
     private native final void native_setup();
     private native final void native_finalize();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 03dc2ea..1a1d0f3 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1258,7 +1258,13 @@
                         e.printStackTrace();
                     }
                     baseSetStartDelayMs(0);
-                    startImpl();
+                    try {
+                        startImpl();
+                    } catch (IllegalStateException e) {
+                        // fail silently for a state exception when it is happening after
+                        // a delayed start, as the player state could have changed between the
+                        // call to start() and the execution of startImpl()
+                    }
                 }
             }.start();
         }
diff --git a/media/java/android/media/session/IOnMediaKeyListener.aidl b/media/java/android/media/session/IOnMediaKeyListener.aidl
index 7752357..aa98ea3 100644
--- a/media/java/android/media/session/IOnMediaKeyListener.aidl
+++ b/media/java/android/media/session/IOnMediaKeyListener.aidl
@@ -22,7 +22,7 @@
  * Listener to handle media key.
  * @hide
  */
-interface IOnMediaKeyListener {
+oneway interface IOnMediaKeyListener {
     void onMediaKey(in KeyEvent event, in ResultReceiver result);
 }
 
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 2f6e260..a146c62 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -16,6 +16,7 @@
 package android.media.session;
 
 import android.content.Intent;
+import android.media.MediaDescription;
 import android.media.Rating;
 import android.net.Uri;
 import android.os.Bundle;
@@ -49,6 +50,10 @@
     void onRepeatMode(int repeatMode);
     void onShuffleMode(boolean enabled);
     void onCustomAction(String action, in Bundle args);
+    void onAddQueueItem(in MediaDescription description);
+    void onAddQueueItemAt(in MediaDescription description, int index);
+    void onRemoveQueueItem(in MediaDescription description);
+    void onRemoveQueueItemAt(int index);
 
     // These callbacks are for volume handling
     void onAdjustVolume(int direction);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e92758c..7b5233a 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -18,6 +18,7 @@
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
+import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.session.ISessionControllerCallback;
@@ -51,6 +52,11 @@
     MediaMetadata getMetadata();
     PlaybackState getPlaybackState();
     ParceledListSlice getQueue();
+    void addQueueItem(in MediaDescription description);
+    void addQueueItemAt(in MediaDescription description, int index);
+    void removeQueueItem(in MediaDescription description);
+    void removeQueueItemAt(int index);
+
     CharSequence getQueueTitle();
     Bundle getExtras();
     int getRatingType();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 8cbf8e1..bab2af2 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -23,6 +23,7 @@
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
@@ -38,6 +39,7 @@
 import android.view.KeyEvent;
 
 import java.lang.ref.WeakReference;
+import java.lang.UnsupportedOperationException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -111,8 +113,7 @@
     }
 
     /**
-     * Get a {@link TransportControls} instance to send transport actions to
-     * the associated session.
+     * Get a {@link TransportControls} instance to send transport actions to this session.
      *
      * @return A transport controls instance.
      */
@@ -151,7 +152,7 @@
         try {
             return mSessionBinder.getPlaybackState();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getPlaybackState.", e);
+            Log.wtf(TAG, "Error calling getPlaybackState", e);
             return null;
         }
     }
@@ -165,7 +166,7 @@
         try {
             return mSessionBinder.getMetadata();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getMetadata.", e);
+            Log.wtf(TAG, "Error calling getMetadata", e);
             return null;
         }
     }
@@ -183,12 +184,103 @@
                 return queue.getList();
             }
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getQueue.", e);
+            Log.wtf(TAG, "Error calling getQueue", e);
         }
         return null;
     }
 
     /**
+     * Add a queue item from the given {@code description} at the end of the play queue
+     * of this session. Not all sessions may support this.
+     *
+     * @param description The {@link MediaDescription} for creating the
+     *                    {@link MediaSession.QueueItem} to be inserted.
+     * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+     */
+    public void addQueueItem(MediaDescription description) {
+        try {
+            long flags = mSessionBinder.getFlags();
+            if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
+            mSessionBinder.addQueueItem(description);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling addQueueItem", e);
+        }
+    }
+
+    /**
+     * Add a queue item from the given {@code description} at the specified position
+     * in the play queue of this session. Shifts the queue item currently at that position
+     * (if any) and any subsequent queue items to the right (adds one to their indices).
+     * Not all sessions may support this.
+     *
+     * @param description The {@link MediaDescription} for creating the
+     *                    {@link MediaSession.QueueItem} to be inserted.
+     * @param index The index at which the created {@link MediaSession.QueueItem} is to be inserted.
+     * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+     */
+    public void addQueueItem(MediaDescription description, int index) {
+        try {
+            long flags = mSessionBinder.getFlags();
+            if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
+            mSessionBinder.addQueueItemAt(description, index);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling addQueueItemAt", e);
+        }
+    }
+
+    /**
+     * Remove the first occurrence of the specified {@link MediaSession.QueueItem}
+     * with the given {@link MediaDescription description} in the play queue of the associated
+     * session. Not all sessions may support this.
+     *
+     * @param description The {@link MediaDescription} for denoting the
+     *                    {@link MediaSession.QueueItem} to be removed.
+     * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+     */
+    public void removeQueueItem(MediaDescription description) {
+        try {
+            long flags = mSessionBinder.getFlags();
+            if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
+            mSessionBinder.removeQueueItem(description);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling removeQueueItem", e);
+        }
+    }
+
+    /**
+     * Remove an queue item at the specified position in the play queue
+     * of this session. Not all sessions may support this.
+     *
+     * @param index The index of the element to be removed.
+     * @throws UnsupportedOperationException If this session doesn't support this.
+     * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS
+     */
+    public void removeQueueItemAt(int index) {
+        try {
+            long flags = mSessionBinder.getFlags();
+            if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+                throw new UnsupportedOperationException(
+                        "This session doesn't support queue management operations");
+            }
+            mSessionBinder.removeQueueItemAt(index);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling removeQueueItemAt", e);
+        }
+    }
+
+    /**
      * Get the queue title for this session.
      */
     public @Nullable CharSequence getQueueTitle() {
@@ -230,7 +322,7 @@
         try {
             return mSessionBinder.getRatingType();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getRatingType.", e);
+            Log.wtf(TAG, "Error calling getRatingType", e);
             return Rating.RATING_NONE;
         }
     }
@@ -245,7 +337,7 @@
         try {
             return mSessionBinder.getRepeatMode();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getRepeatMode.", e);
+            Log.wtf(TAG, "Error calling getRepeatMode", e);
             return PlaybackState.REPEAT_MODE_NONE;
         }
     }
@@ -259,7 +351,7 @@
         try {
             return mSessionBinder.isShuffleModeEnabled();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling isShuffleModeEnabled.", e);
+            Log.wtf(TAG, "Error calling isShuffleModeEnabled", e);
             return false;
         }
     }
@@ -273,7 +365,7 @@
         try {
             return mSessionBinder.getFlags();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getFlags.", e);
+            Log.wtf(TAG, "Error calling getFlags", e);
         }
         return 0;
     }
@@ -290,7 +382,7 @@
                     result.maxVolume, result.currentVolume);
 
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getAudioInfo.", e);
+            Log.wtf(TAG, "Error calling getAudioInfo", e);
         }
         return null;
     }
@@ -305,7 +397,7 @@
         try {
             return mSessionBinder.getLaunchPendingIntent();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getPendingIntent.", e);
+            Log.wtf(TAG, "Error calling getPendingIntent", e);
         }
         return null;
     }
@@ -334,7 +426,7 @@
         try {
             mSessionBinder.setVolumeTo(value, flags, mContext.getPackageName());
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling setVolumeTo.", e);
+            Log.wtf(TAG, "Error calling setVolumeTo", e);
         }
     }
 
@@ -355,7 +447,7 @@
         try {
             mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName());
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
+            Log.wtf(TAG, "Error calling adjustVolumeBy", e);
         }
     }
 
@@ -421,7 +513,7 @@
         try {
             mSessionBinder.sendCommand(command, args, cb);
         } catch (RemoteException e) {
-            Log.d(TAG, "Dead object in sendCommand.", e);
+            Log.d(TAG, "Dead object in sendCommand", e);
         }
     }
 
@@ -435,7 +527,7 @@
             try {
                 mPackageName = mSessionBinder.getPackageName();
             } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in getPackageName.", e);
+                Log.d(TAG, "Dead object in getPackageName", e);
             }
         }
         return mPackageName;
@@ -452,7 +544,7 @@
             try {
                 mTag = mSessionBinder.getTag();
             } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in getTag.", e);
+                Log.d(TAG, "Dead object in getTag", e);
             }
         }
         return mTag;
@@ -652,7 +744,7 @@
             try {
                 mSessionBinder.prepare();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare.", e);
+                Log.wtf(TAG, "Error calling prepare", e);
             }
         }
 
@@ -671,12 +763,12 @@
         public void prepareFromMediaId(String mediaId, Bundle extras) {
             if (TextUtils.isEmpty(mediaId)) {
                 throw new IllegalArgumentException(
-                        "You must specify a non-empty String for prepareFromMediaId.");
+                        "You must specify a non-empty String for prepareFromMediaId");
             }
             try {
                 mSessionBinder.prepareFromMediaId(mediaId, extras);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
+                Log.wtf(TAG, "Error calling prepare(" + mediaId + ")", e);
             }
         }
 
@@ -702,7 +794,7 @@
             try {
                 mSessionBinder.prepareFromSearch(query, extras);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
+                Log.wtf(TAG, "Error calling prepare(" + query + ")", e);
             }
         }
 
@@ -721,12 +813,12 @@
         public void prepareFromUri(Uri uri, Bundle extras) {
             if (uri == null || Uri.EMPTY.equals(uri)) {
                 throw new IllegalArgumentException(
-                        "You must specify a non-empty Uri for prepareFromUri.");
+                        "You must specify a non-empty Uri for prepareFromUri");
             }
             try {
                 mSessionBinder.prepareFromUri(uri, extras);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
+                Log.wtf(TAG, "Error calling prepare(" + uri + ")", e);
             }
         }
 
@@ -737,7 +829,7 @@
             try {
                 mSessionBinder.play();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play.", e);
+                Log.wtf(TAG, "Error calling play", e);
             }
         }
 
@@ -751,12 +843,12 @@
         public void playFromMediaId(String mediaId, Bundle extras) {
             if (TextUtils.isEmpty(mediaId)) {
                 throw new IllegalArgumentException(
-                        "You must specify a non-empty String for playFromMediaId.");
+                        "You must specify a non-empty String for playFromMediaId");
             }
             try {
                 mSessionBinder.playFromMediaId(mediaId, extras);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
+                Log.wtf(TAG, "Error calling play(" + mediaId + ")", e);
             }
         }
 
@@ -778,7 +870,7 @@
             try {
                 mSessionBinder.playFromSearch(query, extras);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + query + ").", e);
+                Log.wtf(TAG, "Error calling play(" + query + ")", e);
             }
         }
 
@@ -792,12 +884,12 @@
         public void playFromUri(Uri uri, Bundle extras) {
             if (uri == null || Uri.EMPTY.equals(uri)) {
                 throw new IllegalArgumentException(
-                        "You must specify a non-empty Uri for playFromUri.");
+                        "You must specify a non-empty Uri for playFromUri");
             }
             try {
                 mSessionBinder.playFromUri(uri, extras);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + uri + ").", e);
+                Log.wtf(TAG, "Error calling play(" + uri + ")", e);
             }
         }
 
@@ -809,7 +901,7 @@
             try {
                 mSessionBinder.skipToQueueItem(id);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
+                Log.wtf(TAG, "Error calling skipToItem(" + id + ")", e);
             }
         }
 
@@ -821,7 +913,7 @@
             try {
                 mSessionBinder.pause();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling pause.", e);
+                Log.wtf(TAG, "Error calling pause", e);
             }
         }
 
@@ -833,7 +925,7 @@
             try {
                 mSessionBinder.stop();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling stop.", e);
+                Log.wtf(TAG, "Error calling stop", e);
             }
         }
 
@@ -846,7 +938,7 @@
             try {
                 mSessionBinder.seekTo(pos);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling seekTo.", e);
+                Log.wtf(TAG, "Error calling seekTo", e);
             }
         }
 
@@ -858,7 +950,7 @@
             try {
                 mSessionBinder.fastForward();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling fastForward.", e);
+                Log.wtf(TAG, "Error calling fastForward", e);
             }
         }
 
@@ -869,7 +961,7 @@
             try {
                 mSessionBinder.next();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling next.", e);
+                Log.wtf(TAG, "Error calling next", e);
             }
         }
 
@@ -881,7 +973,7 @@
             try {
                 mSessionBinder.rewind();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling rewind.", e);
+                Log.wtf(TAG, "Error calling rewind", e);
             }
         }
 
@@ -892,7 +984,7 @@
             try {
                 mSessionBinder.previous();
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling previous.", e);
+                Log.wtf(TAG, "Error calling previous", e);
             }
         }
 
@@ -907,7 +999,7 @@
             try {
                 mSessionBinder.rate(rating);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling rate.", e);
+                Log.wtf(TAG, "Error calling rate", e);
             }
         }
 
@@ -923,7 +1015,7 @@
             try {
                 mSessionBinder.repeatMode(repeatMode);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling setRepeatMode.", e);
+                Log.wtf(TAG, "Error calling setRepeatMode", e);
             }
         }
 
@@ -936,7 +1028,7 @@
             try {
                 mSessionBinder.shuffleMode(enabled);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling shuffleMode.", e);
+                Log.wtf(TAG, "Error calling shuffleMode", e);
             }
         }
 
@@ -950,7 +1042,7 @@
         public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
                     @Nullable Bundle args) {
             if (customAction == null) {
-                throw new IllegalArgumentException("CustomAction cannot be null.");
+                throw new IllegalArgumentException("CustomAction cannot be null");
             }
             sendCustomAction(customAction.getAction(), args);
         }
@@ -966,12 +1058,12 @@
          */
         public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
             if (TextUtils.isEmpty(action)) {
-                throw new IllegalArgumentException("CustomAction cannot be null.");
+                throw new IllegalArgumentException("CustomAction cannot be null");
             }
             try {
                 mSessionBinder.sendCustomAction(action, args);
             } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in sendCustomAction.", e);
+                Log.d(TAG, "Dead object in sendCustomAction", e);
             }
         }
     }
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 84dc93a..bee3f52 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,6 +87,12 @@
     public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
 
     /**
+     * Set this flag on the session to indicate that it handles queue
+     * management commands through its {@link Callback}.
+     */
+    public static final int FLAG_HANDLES_QUEUE_COMMANDS = 1 << 2;
+
+    /**
      * System only flag for a session that needs to have priority over all other
      * sessions. This flag ensures this session will receive media button events
      * regardless of the current ordering in the system.
@@ -100,6 +106,7 @@
     @IntDef(flag = true, value = {
             FLAG_HANDLES_MEDIA_BUTTONS,
             FLAG_HANDLES_TRANSPORT_CONTROLS,
+            FLAG_HANDLES_QUEUE_COMMANDS,
             FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
     public @interface SessionFlags { }
 
@@ -645,6 +652,22 @@
         postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
     }
 
+    private void dispatchAddQueueItem(MediaDescription description) {
+        postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM, description);
+    }
+
+    private void dispatchAddQueueItem(MediaDescription description, int index) {
+        postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM_AT, description, index);
+    }
+
+    private void dispatchRemoveQueueItem(MediaDescription description) {
+        postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM, description);
+    }
+
+    private void dispatchRemoveQueueItemAt(int index) {
+        postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM_AT, index);
+    }
+
     private void dispatchMediaButton(Intent mediaButtonIntent) {
         postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent);
     }
@@ -666,10 +689,22 @@
         postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd);
     }
 
+    private void postToCallback(int what, int arg1) {
+        postToCallback(what, null, arg1);
+    }
+
     private void postToCallback(int what, Object obj) {
         postToCallback(what, obj, null);
     }
 
+    private void postToCallback(int what, Object obj, int arg1) {
+        synchronized (mLock) {
+            if (mCallback != null) {
+                mCallback.post(what, obj, arg1);
+            }
+        }
+    }
+
     private void postToCallback(int what, Object obj, Bundle extras) {
         synchronized (mLock) {
             if (mCallback != null) {
@@ -1043,6 +1078,47 @@
          */
         public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
         }
+
+        /**
+         * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given
+         * {@link MediaDescription description} at the end of the play queue.
+         *
+         * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be
+         *                    inserted.
+         */
+        public void onAddQueueItem(MediaDescription description) {
+        }
+
+        /**
+         * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given
+         * {@link MediaDescription description} at the specified position in the play queue.
+         *
+         * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be
+         *                    inserted.
+         * @param index The index at which the created {@link QueueItem} is to be inserted.
+         */
+        public void onAddQueueItem(MediaDescription description, int index) {
+        }
+
+        /**
+         * Called when a {@link MediaController} wants to remove the first occurrence of the
+         * specified {@link QueueItem} with the given {@link MediaDescription description}
+         * in the play queue.
+         *
+         * @param description The {@link MediaDescription} for denoting the {@link QueueItem} to be
+         *                    removed.
+         */
+        public void onRemoveQueueItem(MediaDescription description) {
+        }
+
+        /**
+         * Called when a {@link MediaController} wants to remove a {@link QueueItem} at the
+         * specified position in the play queue.
+         *
+         * @param index The index of the element to be removed.
+         */
+        public void onRemoveQueueItemAt(int index) {
+        }
     }
 
     /**
@@ -1239,6 +1315,38 @@
         }
 
         @Override
+        public void onAddQueueItem(MediaDescription description) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchAddQueueItem(description);
+            }
+        }
+
+        @Override
+        public void onAddQueueItemAt(MediaDescription description, int index) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchAddQueueItem(description, index);
+            }
+        }
+
+        @Override
+        public void onRemoveQueueItem(MediaDescription description) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchRemoveQueueItem(description);
+            }
+        }
+
+        @Override
+        public void onRemoveQueueItemAt(int index) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchRemoveQueueItemAt(index);
+            }
+        }
+
+        @Override
         public void onAdjustVolume(int direction) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -1376,6 +1484,10 @@
         private static final int MSG_CUSTOM_ACTION = 22;
         private static final int MSG_ADJUST_VOLUME = 23;
         private static final int MSG_SET_VOLUME = 24;
+        private static final int MSG_ADD_QUEUE_ITEM = 25;
+        private static final int MSG_ADD_QUEUE_ITEM_AT = 26;
+        private static final int MSG_REMOVE_QUEUE_ITEM = 27;
+        private static final int MSG_REMOVE_QUEUE_ITEM_AT = 28;
 
         private MediaSession.Callback mCallback;
 
@@ -1465,7 +1577,7 @@
                     mCallback.onSetRating((Rating) msg.obj);
                     break;
                 case MSG_REPEAT_MODE:
-                    mCallback.onSetRepeatMode((int) msg.obj);
+                    mCallback.onSetRepeatMode(msg.arg1);
                     break;
                 case MSG_SHUFFLE_MODE:
                     mCallback.onSetShuffleModeEnabled((boolean) msg.obj);
@@ -1473,12 +1585,24 @@
                 case MSG_CUSTOM_ACTION:
                     mCallback.onCustomAction((String) msg.obj, msg.getData());
                     break;
+                case MSG_ADD_QUEUE_ITEM:
+                    mCallback.onAddQueueItem((MediaDescription) msg.obj);
+                    break;
+                case MSG_ADD_QUEUE_ITEM_AT:
+                    mCallback.onAddQueueItem((MediaDescription) msg.obj, msg.arg1);
+                    break;
+                case MSG_REMOVE_QUEUE_ITEM:
+                    mCallback.onRemoveQueueItem((MediaDescription) msg.obj);
+                    break;
+                case MSG_REMOVE_QUEUE_ITEM_AT:
+                    mCallback.onRemoveQueueItemAt(msg.arg1);
+                    break;
                 case MSG_ADJUST_VOLUME:
                     synchronized (mLock) {
                         vp = mVolumeProvider;
                     }
                     if (vp != null) {
-                        vp.onAdjustVolume((int) msg.obj);
+                        vp.onAdjustVolume(msg.arg1);
                     }
                     break;
                 case MSG_SET_VOLUME:
@@ -1486,7 +1610,7 @@
                         vp = mVolumeProvider;
                     }
                     if (vp != null) {
-                        vp.onSetVolumeTo((int) msg.obj);
+                        vp.onSetVolumeTo(msg.arg1);
                     }
                     break;
             }
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 8ea0d8a..ddbd542e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -29,6 +30,8 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -359,6 +362,285 @@
         String COLUMN_PACKAGE_NAME = "package_name";
     }
 
+    /**
+     * Common base for the tables of TV programs.
+     */
+    public interface BaseProgramColumns extends BaseTvColumns {
+        /**
+         * The ID of the TV channel that provides this TV program.
+         *
+         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: INTEGER (long)
+         */
+        public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+        /**
+         * The title of this TV program.
+         *
+         * <p>If this program is an episodic TV show, it is recommended that the title is the series
+         * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
+         * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_TITLE = "title";
+
+        /**
+         * The season display number of this TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+
+        /**
+         * The title of the season for this TV program for episodic TV shows.
+         *
+         * <p>This is an optional field supplied only when the season has a special title
+         * (e.g. The Final Season). If provided, the applications should display it instead of
+         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
+         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
+         * "Season The Final Season"). When displaying multiple programs, the order should be based
+         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SEASON_TITLE = "season_title";
+
+        /**
+         * The episode display number of this TV program for episodic TV shows.
+         *
+         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
+         * does not necessarily be numeric. (e.g. 12B)
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+
+        /**
+         * The episode title of this TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_EPISODE_TITLE = "episode_title";
+
+        /**
+         * The comma-separated canonical genre string of this TV program.
+         *
+         * <p>Canonical genres are defined in {@link Genres}. Use {@link Genres#encode} to create a
+         * text that can be stored in this column. Use {@link Genres#decode} to get the canonical
+         * genre strings from the text stored in the column.
+         *
+         * <p>Type: TEXT
+         * @see Genres
+         * @see Genres#encode
+         * @see Genres#decode
+         */
+        public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+
+        /**
+         * The short description of this TV program that is displayed to the user by default.
+         *
+         * <p>It is recommended to limit the length of the descriptions to 256 characters.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+
+        /**
+         * The detailed, lengthy description of this TV program that is displayed only when the user
+         * wants to see more information.
+         *
+         * <p>TV input services should leave this field empty if they have no additional details
+         * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+
+        /**
+         * The width of the video for this TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
+         * resolution of the current TV program. Can be empty if it is not known initially or the
+         * program does not convey any video such as the programs from type
+         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_VIDEO_WIDTH = "video_width";
+
+        /**
+         * The height of the video for this TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
+         * resolution of the current TV program. Can be empty if it is not known initially or the
+         * program does not convey any video such as the programs from type
+         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+
+        /**
+         * The comma-separated audio languages of this TV program.
+         *
+         * <p>This is used to describe available audio languages included in the program. Use either
+         * ISO 639-1 or 639-2/T codes.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+
+        /**
+         * The comma-separated content ratings of this TV program.
+         *
+         * <p>This is used to describe the content rating(s) of this program. Each comma-separated
+         * content rating sub-string should be generated by calling
+         * {@link TvContentRating#flattenToString}. Note that in most cases the program content is
+         * rated by a single rating system, thus resulting in a corresponding single sub-string that
+         * does not require comma separation and multiple sub-strings appear only when the program
+         * content is rated by two or more content rating systems. If any of those ratings is
+         * specified as "blocked rating" in the user's parental control settings, the TV input
+         * service should block the current content and wait for the signal that it is okay to
+         * unblock.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_CONTENT_RATING = "content_rating";
+
+        /**
+         * The URI for the poster art of this TV program.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+
+        /**
+         * The URI for the thumbnail of this TV program.
+         *
+         * <p>The system can generate a thumbnail from the poster art if this column is not
+         * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
+         * just a scaled image of the poster art.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+
+        /**
+         * The flag indicating whether this TV program is searchable or not.
+         *
+         * <p>The columns of searchable programs can be read by other applications that have proper
+         * permission. Care must be taken not to open sensitive data.
+         *
+         * <p>A value of 1 indicates that the program is searchable and its columns can be read by
+         * other applications, a value of 0 indicates that the program is hidden and its columns can
+         * be read only by the package that owns the program and the system. If not specified, this
+         * value is set to 1 (searchable) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_SEARCHABLE = "searchable";
+
+        /**
+         * Internal data used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: BLOB
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+
+        /**
+         * The version number of this row entry used by TV input services.
+         *
+         * <p>This is best used by sync adapters to identify the rows to update. The number can be
+         * defined by individual TV input services. One may assign the same value as
+         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
+         * broadcast.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_VERSION_NUMBER = "version_number";
+    }
+
     /** Column definitions for the TV channels table. */
     public static final class Channels implements BaseTvColumns {
 
@@ -372,6 +654,37 @@
         /** The MIME type of a single TV channel. */
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
 
+        /** @hide */
+        @StringDef({
+                TYPE_OTHER,
+                TYPE_NTSC,
+                TYPE_PAL,
+                TYPE_SECAM,
+                TYPE_DVB_T,
+                TYPE_DVB_T2,
+                TYPE_DVB_S,
+                TYPE_DVB_S2,
+                TYPE_DVB_C,
+                TYPE_DVB_C2,
+                TYPE_DVB_H,
+                TYPE_DVB_SH,
+                TYPE_ATSC_T,
+                TYPE_ATSC_C,
+                TYPE_ATSC_M_H,
+                TYPE_ISDB_T,
+                TYPE_ISDB_TB,
+                TYPE_ISDB_S,
+                TYPE_ISDB_C,
+                TYPE_1SEG,
+                TYPE_DTMB,
+                TYPE_CMMB,
+                TYPE_T_DMB,
+                TYPE_S_DMB,
+                TYPE_PREVIEW,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Type {}
+
         /**
          * A generic channel type.
          *
@@ -554,6 +867,15 @@
          */
         public static final String TYPE_PREVIEW = "TYPE_PREVIEW";
 
+        /** @hide */
+        @StringDef({
+                SERVICE_TYPE_OTHER,
+                SERVICE_TYPE_AUDIO_VIDEO,
+                SERVICE_TYPE_AUDIO,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface ServiceType {}
+
         /** A generic service type. */
         public static final String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
 
@@ -563,6 +885,22 @@
         /** The service type for radio channels that have audio only. */
         public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
 
+        /** @hide */
+        @StringDef({
+                VIDEO_FORMAT_240P,
+                VIDEO_FORMAT_360P,
+                VIDEO_FORMAT_480I,
+                VIDEO_FORMAT_576I,
+                VIDEO_FORMAT_576P,
+                VIDEO_FORMAT_720P,
+                VIDEO_FORMAT_1080I,
+                VIDEO_FORMAT_1080P,
+                VIDEO_FORMAT_2160P,
+                VIDEO_FORMAT_4320P,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface VideoFormat {}
+
         /** The video format for 240p. */
         public static final String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
 
@@ -596,6 +934,17 @@
         /** The video format for 4320p. */
         public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
 
+        /** @hide */
+        @StringDef({
+                VIDEO_RESOLUTION_SD,
+                VIDEO_RESOLUTION_ED,
+                VIDEO_RESOLUTION_HD,
+                VIDEO_RESOLUTION_FHD,
+                VIDEO_RESOLUTION_UHD,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface VideoResolution {}
+
         /** The video resolution for standard-definition. */
         public static final String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
 
@@ -634,7 +983,7 @@
          * @see #COLUMN_VIDEO_FORMAT
          */
         @Nullable
-        public static final String getVideoResolution(String videoFormat) {
+        public static final String getVideoResolution(@VideoFormat String videoFormat) {
             return VIDEO_FORMAT_TO_RESOLUTION_MAP.get(videoFormat);
         }
 
@@ -1088,7 +1437,7 @@
      * <p>By default, the query results will be sorted by
      * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} in ascending order.
      */
-    public static final class Programs implements BaseTvColumns {
+    public static final class Programs implements BaseProgramColumns {
 
         /** The content:// style URI for this table. */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -1100,6 +1449,24 @@
         /** The MIME type of a single TV program. */
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
 
+        /** @hide */
+        @StringDef({
+                TYPE_MOVIE,
+                TYPE_TV_SERIES,
+                TYPE_TV_SEASON,
+                TYPE_TV_EPISODE,
+                TYPE_CLIP,
+                TYPE_EVENT,
+                TYPE_CHANNEL,
+                TYPE_TRACK,
+                TYPE_ALBUM,
+                TYPE_ARTIST,
+                TYPE_PLAYLIST,
+                TYPE_STATION,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Type {}
+
         /**
          * The program type for movie.
          *
@@ -1184,6 +1551,15 @@
          */
         public static final String TYPE_STATION = "TYPE_STATION";
 
+        /** @hide */
+        @StringDef({
+                WATCH_NEXT_TYPE_CONTINUE,
+                WATCH_NEXT_TYPE_NEXT,
+                WATCH_NEXT_TYPE_NEW,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface WatchNextType {}
+
         /**
          * The watch next type for CONTINUE.
          *
@@ -1205,6 +1581,16 @@
          */
         public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
 
+        /** @hide */
+        @StringDef({
+                ASPECT_RATIO_16_9,
+                ASPECT_RATIO_3_2,
+                ASPECT_RATIO_1_1,
+                ASPECT_RATIO_2_3,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface AspectRatio {}
+
         /**
          * The aspect ratio for 16:9.
          *
@@ -1237,6 +1623,15 @@
          */
         public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
 
+        /** @hide */
+        @StringDef({
+                AVAILABILITY_AVAILABLE,
+                AVAILABILITY_FREE_WITH_SUBSCRIPTION,
+                AVAILABILITY_PAID_CONTENT,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Availability {}
+
         /**
          * The availability for "available to this user".
          *
@@ -1260,6 +1655,19 @@
          */
         public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
 
+        /** @hide */
+        @StringDef({
+                INTERACTION_TYPE_LISTENS,
+                INTERACTION_TYPE_FOLLOWERS,
+                INTERACTION_TYPE_FANS,
+                INTERACTION_TYPE_LIKES,
+                INTERACTION_TYPE_THUMBS,
+                INTERACTION_TYPE_VIEWS,
+                INTERACTION_TYPE_VIEWERS,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface InteractionType {}
+
         /**
          * The interaction type for "listens".
          *
@@ -1309,6 +1717,15 @@
          */
         public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
 
+        /** @hide */
+        @StringDef({
+                REVIEW_RATING_STYLE_STARS,
+                REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
+                REVIEW_RATING_STYLE_PERCENTAGE,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface ReviewRatingStyle {}
+
         /**
          * The review rating style for five star rating.
          *
@@ -1333,17 +1750,6 @@
                 "REVIEW_RATING_STYLE_PERCENTAGE";
 
         /**
-         * The ID of the TV channel that provides this TV program.
-         *
-         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
-         *
-         * <p>This is a required field.
-         *
-         * <p>Type: INTEGER (long)
-         */
-        public static final String COLUMN_CHANNEL_ID = "channel_id";
-
-        /**
          * The type of this program content.
          *
          * <p>The value should match one of the followings:
@@ -1382,18 +1788,6 @@
         public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
 
         /**
-         * The title of this TV program.
-         *
-         * <p>If this program is an episodic TV show, it is recommended that the title is the series
-         * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
-         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
-         * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_TITLE = "title";
-
-        /**
          * The season number of this TV program for episodic TV shows.
          *
          * <p>Can be empty.
@@ -1406,34 +1800,6 @@
         public static final String COLUMN_SEASON_NUMBER = "season_number";
 
         /**
-         * The season display number of this TV program for episodic TV shows.
-         *
-         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
-         * does not necessarily be numeric. (e.g. 12B)
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-
-        /**
-         * The title of the season for this TV program for episodic TV shows.
-         *
-         * <p>This is an optional field supplied only when the season has a special title
-         * (e.g. The Final Season). If provided, the applications should display it instead of
-         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
-         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
-         * "Season The Final Season"). When displaying multiple programs, the order should be based
-         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_SEASON_TITLE = "season_title";
-
-        /**
          * The episode number of this TV program for episodic TV shows.
          *
          * <p>Can be empty.
@@ -1445,28 +1811,7 @@
         @Deprecated
         public static final String COLUMN_EPISODE_NUMBER = "episode_number";
 
-        /**
-         * The episode display number of this TV program for episodic TV shows.
-         *
-         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
-         * does not necessarily be numeric. (e.g. 12B)
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-
-        /**
-         * The episode title of this TV program for episodic TV shows.
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_EPISODE_TITLE = "episode_title";
-
-        /**
+            /**
          * The start time of this TV program, in milliseconds since the epoch.
          *
          * <p>The value should be equal to or larger than {@link #COLUMN_END_TIME_UTC_MILLIS} of the
@@ -1509,109 +1854,6 @@
         public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
 
         /**
-         * The comma-separated canonical genre string of this TV program.
-         *
-         * <p>Canonical genres are defined in {@link Genres}. Use {@link Genres#encode} to create a
-         * text that can be stored in this column. Use {@link Genres#decode} to get the canonical
-         * genre strings from the text stored in the column.
-         *
-         * <p>Type: TEXT
-         * @see Genres
-         * @see Genres#encode
-         * @see Genres#decode
-         */
-        public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
-
-        /**
-         * The short description of this TV program that is displayed to the user by default.
-         *
-         * <p>It is recommended to limit the length of the descriptions to 256 characters.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
-
-        /**
-         * The detailed, lengthy description of this TV program that is displayed only when the user
-         * wants to see more information.
-         *
-         * <p>TV input services should leave this field empty if they have no additional details
-         * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_LONG_DESCRIPTION = "long_description";
-
-        /**
-         * The width of the video for this TV program, in the unit of pixels.
-         *
-         * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
-         * resolution of the current TV program. Can be empty if it is not known initially or the
-         * program does not convey any video such as the programs from type
-         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
-         *
-         * <p>Type: INTEGER
-         */
-        public static final String COLUMN_VIDEO_WIDTH = "video_width";
-
-        /**
-         * The height of the video for this TV program, in the unit of pixels.
-         *
-         * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
-         * resolution of the current TV program. Can be empty if it is not known initially or the
-         * program does not convey any video such as the programs from type
-         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
-         *
-         * <p>Type: INTEGER
-         */
-        public static final String COLUMN_VIDEO_HEIGHT = "video_height";
-
-        /**
-         * The comma-separated audio languages of this TV program.
-         *
-         * <p>This is used to describe available audio languages included in the program. Use either
-         * ISO 639-1 or 639-2/T codes.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
-
-        /**
-         * The comma-separated content ratings of this TV program.
-         *
-         * <p>This is used to describe the content rating(s) of this program. Each comma-separated
-         * content rating sub-string should be generated by calling
-         * {@link TvContentRating#flattenToString}. Note that in most cases the program content is
-         * rated by a single rating system, thus resulting in a corresponding single sub-string that
-         * does not require comma separation and multiple sub-strings appear only when the program
-         * content is rated by two or more content rating systems. If any of those ratings is
-         * specified as "blocked rating" in the user's parental control settings, the TV input
-         * service should block the current content and wait for the signal that it is okay to
-         * unblock.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_CONTENT_RATING = "content_rating";
-
-        /**
-         * The URI for the poster art of this TV program.
-         *
-         * <p>The data in the column must be a URL, or a URI in one of the following formats:
-         *
-         * <ul>
-         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
-         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
-         * </li>
-         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
-         * </ul>
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
-
-        /**
          * The aspect ratio of the poster art for this TV program.
          *
          * <p>The value should match one of the followings:
@@ -1625,28 +1867,6 @@
         public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
 
         /**
-         * The URI for the thumbnail of this TV program.
-         *
-         * <p>The system can generate a thumbnail from the poster art if this column is not
-         * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
-         * just a scaled image of the poster art.
-         *
-         * <p>The data in the column must be a URL, or a URI in one of the following formats:
-         *
-         * <ul>
-         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
-         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
-         * </li>
-         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
-         * </ul>
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-
-        /**
          * The aspect ratio of the thumbnail for this TV program.
          *
          * <p>The value should match one of the followings:
@@ -1745,21 +1965,6 @@
         public static final String COLUMN_LIVE = "live";
 
         /**
-         * The flag indicating whether this TV program is searchable or not.
-         *
-         * <p>The columns of searchable programs can be read by other applications that have proper
-         * permission. Care must be taken not to open sensitive data.
-         *
-         * <p>A value of 1 indicates that the program is searchable and its columns can be read by
-         * other applications, a value of 0 indicates that the program is hidden and its columns can
-         * be read only by the package that owns the program and the system. If not specified, this
-         * value is set to 1 (searchable) by default.
-         *
-         * <p>Type: INTEGER (boolean)
-         */
-        public static final String COLUMN_SEARCHABLE = "searchable";
-
-        /**
          * The flag indicating whether recording of this program is prohibited.
          *
          * <p>A value of 1 indicates that recording of this program is prohibited and application
@@ -1772,68 +1977,6 @@
         public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
 
         /**
-         * Internal data used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: BLOB
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-
-        /**
-         * The version number of this row entry used by TV input services.
-         *
-         * <p>This is best used by sync adapters to identify the rows to update. The number can be
-         * defined by individual TV input services. One may assign the same value as
-         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
-         * broadcast.
-         *
-         * <p>Type: INTEGER
-         */
-        public static final String COLUMN_VERSION_NUMBER = "version_number";
-
-        /**
          * The internal ID used by individual TV input services.
          *
          * <p>This is internal to the provider that inserted it, and should not be decoded by other
@@ -1994,6 +2137,29 @@
 
         /** Canonical genres for TV programs. */
         public static final class Genres {
+            /** @hide */
+            @StringDef({
+                    FAMILY_KIDS,
+                    SPORTS,
+                    SHOPPING,
+                    MOVIES,
+                    COMEDY,
+                    TRAVEL,
+                    DRAMA,
+                    EDUCATION,
+                    ANIMAL_WILDLIFE,
+                    NEWS,
+                    GAMING,
+                    ARTS,
+                    ENTERTAINMENT,
+                    LIFE_STYLE,
+                    MUSIC,
+                    PREMIER,
+                    TECH_SCIENCE,
+            })
+            @Retention(RetentionPolicy.SOURCE)
+            public @interface Genre {}
+
             /** The genre for Family/Kids. */
             public static final String FAMILY_KIDS = "FAMILY_KIDS";
 
@@ -2081,7 +2247,7 @@
              * @return an encoded genre string that can be inserted into the
              *         {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
              */
-            public static String encode(@NonNull String... genres) {
+            public static String encode(@NonNull @Genre String... genres) {
                 if (genres == null) {
                     // MNC and before will throw a NPE.
                     return null;
@@ -2120,7 +2286,7 @@
              *            {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
              * @return genre strings.
              */
-            public static String[] decode(@NonNull String genres) {
+            public static @Genre String[] decode(@NonNull String genres) {
                 if (TextUtils.isEmpty(genres)) {
                     // MNC and before will throw a NPE for {@code null} genres.
                     return EMPTY_STRING_ARRAY;
@@ -2180,7 +2346,7 @@
      * <p>By default, the query results will be sorted by {@link #COLUMN_START_TIME_UTC_MILLIS} in
      * ascending order.
      */
-    public static final class RecordedPrograms implements BaseTvColumns {
+    public static final class RecordedPrograms implements BaseProgramColumns {
 
         /** The content:// style URI for this table. */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -2204,83 +2370,6 @@
         public static final String COLUMN_INPUT_ID = "input_id";
 
         /**
-         * The ID of the TV channel that provided this recorded TV program.
-         *
-         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
-         *
-         * <p>This is a required field.
-         *
-         * <p>Type: INTEGER (long)
-         * @see Programs#COLUMN_CHANNEL_ID
-         */
-        public static final String COLUMN_CHANNEL_ID = Programs.COLUMN_CHANNEL_ID;
-
-        /**
-         * The title of this recorded TV program.
-         *
-         * <p>If this recorded program is an episodic TV show, it is recommended that the title is
-         * the series title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
-         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_EPISODE_DISPLAY_NUMBER},
-         * and {@link #COLUMN_EPISODE_TITLE}) are filled in.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_TITLE
-         */
-        public static final String COLUMN_TITLE = Programs.COLUMN_TITLE;
-
-        /**
-         * The season display number of this recorded TV program for episodic TV shows.
-         *
-         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
-         * does not necessarily be numeric. (e.g. 12B)
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_SEASON_DISPLAY_NUMBER =
-                Programs.COLUMN_SEASON_DISPLAY_NUMBER;
-
-        /**
-         * The title of the season for this recorded TV program for episodic TV shows.
-         *
-         * <p>This is an optional field supplied only when the season has a special title
-         * (e.g. The Final Season). If provided, the applications should display it instead of
-         * {@link #COLUMN_SEASON_DISPLAY_NUMBER} without alterations.
-         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
-         * "Season The Final Season"). When displaying multiple programs, the order should be based
-         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_SEASON_TITLE = Programs.COLUMN_SEASON_TITLE;
-
-        /**
-         * The episode display number of this recorded TV program for episodic TV shows.
-         *
-         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
-         * does not necessarily be numeric. (e.g. 12B)
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         */
-        public static final String COLUMN_EPISODE_DISPLAY_NUMBER =
-                Programs.COLUMN_EPISODE_DISPLAY_NUMBER;
-
-        /**
-         * The episode title of this recorded TV program for episodic TV shows.
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_EPISODE_TITLE
-         */
-        public static final String COLUMN_EPISODE_TITLE = Programs.COLUMN_EPISODE_TITLE;
-
-        /**
          * The start time of the original TV program, in milliseconds since the epoch.
          *
          * <p>Type: INTEGER (long)
@@ -2313,154 +2402,6 @@
         public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE;
 
         /**
-         * The comma-separated canonical genre string of this recorded TV program.
-         *
-         * <p>Canonical genres are defined in {@link Programs.Genres}. Use
-         * {@link Programs.Genres#encode Genres.encode()} to create a text that can be stored in
-         * this column. Use {@link Programs.Genres#decode Genres.decode()} to get the canonical
-         * genre strings from the text stored in the column.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_CANONICAL_GENRE
-         * @see Programs.Genres
-         */
-        public static final String COLUMN_CANONICAL_GENRE = Programs.COLUMN_CANONICAL_GENRE;
-
-        /**
-         * The short description of this recorded TV program that is displayed to the user by
-         * default.
-         *
-         * <p>It is recommended to limit the length of the descriptions to 256 characters.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_SHORT_DESCRIPTION
-         */
-        public static final String COLUMN_SHORT_DESCRIPTION = Programs.COLUMN_SHORT_DESCRIPTION;
-
-        /**
-         * The detailed, lengthy description of this recorded TV program that is displayed only when
-         * the user wants to see more information.
-         *
-         * <p>TV input services should leave this field empty if they have no additional details
-         * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_LONG_DESCRIPTION
-         */
-        public static final String COLUMN_LONG_DESCRIPTION = Programs.COLUMN_LONG_DESCRIPTION;
-
-        /**
-         * The width of the video for this recorded TV program, in the unit of pixels.
-         *
-         * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
-         * resolution of the current recorded TV program. Can be empty if it is not known or the
-         * recorded program does not convey any video.
-         *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_VIDEO_WIDTH
-         */
-        public static final String COLUMN_VIDEO_WIDTH = Programs.COLUMN_VIDEO_WIDTH;
-
-        /**
-         * The height of the video for this recorded TV program, in the unit of pixels.
-         *
-         * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
-         * resolution of the current recorded TV program. Can be empty if it is not known or the
-         * recorded program does not convey any video.
-         *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_VIDEO_HEIGHT
-         */
-        public static final String COLUMN_VIDEO_HEIGHT = Programs.COLUMN_VIDEO_HEIGHT;
-
-        /**
-         * The comma-separated audio languages of this recorded TV program.
-         *
-         * <p>This is used to describe available audio languages included in the recorded program.
-         * Use either ISO 639-1 or 639-2/T codes.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_AUDIO_LANGUAGE
-         */
-        public static final String COLUMN_AUDIO_LANGUAGE = Programs.COLUMN_AUDIO_LANGUAGE;
-
-        /**
-         * The comma-separated content ratings of this recorded TV program.
-         *
-         * <p>This is used to describe the content rating(s) of this recorded program. Each
-         * comma-separated content rating sub-string should be generated by calling
-         * {@link TvContentRating#flattenToString}. Note that in most cases the recorded program
-         * content is rated by a single rating system, thus resulting in a corresponding single
-         * sub-string that does not require comma separation and multiple sub-strings appear only
-         * when the recorded program content is rated by two or more content rating systems. If any
-         * of those ratings is specified as "blocked rating" in the user's parental control
-         * settings, the TV input service should block the current content and wait for the signal
-         * that it is okay to unblock.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_CONTENT_RATING
-         */
-        public static final String COLUMN_CONTENT_RATING = Programs.COLUMN_CONTENT_RATING;
-
-        /**
-         * The URI for the poster art of this recorded TV program.
-         *
-         * <p>The data in the column must be a URL, or a URI in one of the following formats:
-         *
-         * <ul>
-         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
-         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
-         * </li>
-         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
-         * </ul>
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_POSTER_ART_URI
-         */
-        public static final String COLUMN_POSTER_ART_URI = Programs.COLUMN_POSTER_ART_URI;
-
-        /**
-         * The URI for the thumbnail of this recorded TV program.
-         *
-         * <p>The system can generate a thumbnail from the poster art if this column is not
-         * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
-         * just a scaled image of the poster art.
-         *
-         * <p>The data in the column must be a URL, or a URI in one of the following formats:
-         *
-         * <ul>
-         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
-         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
-         * </li>
-         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
-         * </ul>
-         *
-         * <p>Can be empty.
-         *
-         * <p>Type: TEXT
-         * @see Programs#COLUMN_THUMBNAIL_URI
-         */
-        public static final String COLUMN_THUMBNAIL_URI = Programs.COLUMN_THUMBNAIL_URI;
-
-        /**
-         * The flag indicating whether this recorded TV program is searchable or not.
-         *
-         * <p>The columns of searchable recorded programs can be read by other applications that
-         * have proper permission. Care must be taken not to open sensitive data.
-         *
-         * <p>A value of 1 indicates that the recorded program is searchable and its columns can be
-         * read by other applications, a value of 0 indicates that the recorded program is hidden
-         * and its columns can be read only by the package that owns the recorded program and the
-         * system. If not specified, this value is set to 1 (searchable) by default.
-         *
-         * <p>Type: INTEGER (boolean)
-         * @see Programs#COLUMN_SEARCHABLE
-         */
-        public static final String COLUMN_SEARCHABLE = Programs.COLUMN_SEARCHABLE;
-
-        /**
          * The URI of the recording data for this recorded program.
          *
          * <p>Together with {@link #COLUMN_RECORDING_DATA_BYTES}, applications can use this
@@ -2510,80 +2451,6 @@
         public static final String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS =
                 "recording_expire_time_utc_millis";
 
-
-        /**
-         * Internal data used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: BLOB
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_DATA
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_DATA =
-                Programs.COLUMN_INTERNAL_PROVIDER_DATA;
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 =
-                Programs.COLUMN_INTERNAL_PROVIDER_FLAG1;
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 =
-                Programs.COLUMN_INTERNAL_PROVIDER_FLAG2;
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 =
-                Programs.COLUMN_INTERNAL_PROVIDER_FLAG3;
-
-        /**
-         * Internal integer flag used by individual TV input services.
-         *
-         * <p>This is internal to the provider that inserted it, and should not be decoded by other
-         * apps.
-         *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
-         */
-        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 =
-                Programs.COLUMN_INTERNAL_PROVIDER_FLAG4;
-
-        /**
-         * The version number of this row entry used by TV input services.
-         *
-         * <p>This is best used by sync adapters to identify the rows to update. The number can be
-         * defined by individual TV input services. One may assign the same value as
-         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
-         * broadcast.
-         *
-         * <p>Type: INTEGER
-         * @see Programs#COLUMN_VERSION_NUMBER
-         */
-        public static final String COLUMN_VERSION_NUMBER = Programs.COLUMN_VERSION_NUMBER;
-
         private RecordedPrograms() {}
     }
 
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 4de1d00..2008f8d 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include "android_media_MediaExtractor.h"
+#include "android_media_MediaMetricsJNI.h"
 
 #include "android_media_Utils.h"
 #include "android_runtime/AndroidRuntime.h"
@@ -240,6 +241,13 @@
     return OK;
 }
 
+status_t JMediaExtractor::getMetrics(Parcel *reply) const {
+
+    status_t status = mImpl->getMetrics(reply);
+    return status;
+}
+
+
 status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
     return mImpl->getSampleMeta(sampleMeta);
 }
@@ -767,6 +775,38 @@
     android_media_MediaExtractor_release(env, thiz);
 }
 
+static jobject
+android_media_MediaExtractor_getMetrics(JNIEnv * env, jobject thiz)
+{
+    ALOGV("android_media_MediaExtractor_getMetrics");
+
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+    if (extractor == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    // get what we have for the metrics from the codec
+    Parcel reply;
+    status_t err = extractor->getMetrics(&reply);
+    if (err != OK) {
+        ALOGE("getMetrics failed");
+        return (jobject) NULL;
+    }
+
+    // build and return the Bundle
+    MediaAnalyticsItem *item = new MediaAnalyticsItem;
+    item->readFromParcel(reply);
+    jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
+
+    // housekeeping
+    delete item;
+    item = NULL;
+
+    return mybundle;
+}
+
+
 static const JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaExtractor_release },
 
@@ -826,6 +866,9 @@
 
     { "hasCacheReachedEndOfStream", "()Z",
       (void *)android_media_MediaExtractor_hasCacheReachedEOS },
+
+    {"getMetrics",          "()Landroid/os/Bundle;",
+      (void *)android_media_MediaExtractor_getMetrics},
 };
 
 int register_android_media_MediaExtractor(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 9f62506..c747ef5 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -60,6 +60,7 @@
     status_t getSampleTime(int64_t *sampleTimeUs);
     status_t getSampleFlags(uint32_t *sampleFlags);
     status_t getSampleMeta(sp<MetaData> *sampleMeta);
+    status_t getMetrics(Parcel *reply) const;
 
     bool getCachedDuration(int64_t *durationUs, bool *eos) const;
 
diff --git a/native/android/hardware_buffer.cpp b/native/android/hardware_buffer.cpp
index 2f75c10..e5e928d 100644
--- a/native/android/hardware_buffer.cpp
+++ b/native/android/hardware_buffer.cpp
@@ -26,10 +26,11 @@
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 #include <binder/Binder.h>
 #include <binder/Parcel.h>
-#include <cutils/native_handle.h>
 #include <binder/IServiceManager.h>
+#include <cutils/native_handle.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/IGraphicBufferAlloc.h>
+#include <hardware/gralloc1.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/Flattenable.h>
 #include <utils/Log.h>
@@ -96,10 +97,14 @@
     }
 
     status_t err;
-    uint32_t usage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(
-            desc->usage0, desc->usage1);
+    uint64_t producerUsage = 0;
+    uint64_t consumerUsage = 0;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(desc->usage0,
+            desc->usage1, &producerUsage, &consumerUsage);
     sp<GraphicBuffer> gbuffer = allocator->createGraphicBuffer(desc->width,
-            desc->height, format, desc->layers, usage, &err);
+            desc->height, format, desc->layers, producerUsage, consumerUsage,
+            std::string("AHardwareBuffer pid [") + std::to_string(getpid()) +
+            "]", &err);
     if (err != NO_ERROR) {
         return err;
     }
@@ -131,7 +136,7 @@
     outDesc->layers = gbuffer->getLayerCount();
     outDesc->usage0 =
             android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
-                    gbuffer->getUsage());
+                    gbuffer->getUsage(), gbuffer->getUsage());
     outDesc->usage1 = 0;
     outDesc->format = android_hardware_HardwareBuffer_convertFromPixelFormat(
             static_cast<uint32_t>(gbuffer->getPixelFormat()));
@@ -148,15 +153,19 @@
         return BAD_VALUE;
     }
 
-    uint32_t usage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(
-            usage0, 0);
+    uint64_t producerUsage = 0;
+    uint64_t consumerUsage = 0;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage0, 0,
+            &producerUsage, &consumerUsage);
     GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+    Rect bounds;
     if (!rect) {
-        return gBuffer->lockAsync(usage, outVirtualAddress, fence);
+        bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight()));
     } else {
-        Rect bounds(rect->left, rect->top, rect->right, rect->bottom);
-        return gBuffer->lockAsync(usage, bounds, outVirtualAddress, fence);
+        bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
     }
+    return gBuffer->lockAsync(producerUsage, consumerUsage, bounds,
+            outVirtualAddress, fence);
 }
 
 int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
diff --git a/opengl/java/android/opengl/GLU.java b/opengl/java/android/opengl/GLU.java
index ed64556..ef9bf167 100644
--- a/opengl/java/android/opengl/GLU.java
+++ b/opengl/java/android/opengl/GLU.java
@@ -203,8 +203,8 @@
      * @param view the current view, {x, y, width, height}
      * @param viewOffset the offset into the view array where the view vector
      *        data starts.
-     * @param obj the output vector {objX, objY, objZ}, that returns the
-     *        computed object coordinates.
+     * @param obj the output vector {objX, objY, objZ, objW}, that returns the
+     *        computed homogeneous object coordinates.
      * @param objOffset the offset into the obj array where the obj vector data
      *        starts.
      * @return A return value of GL10.GL_TRUE indicates success, a return value
diff --git a/packages/CompanionDeviceManager/Android.mk b/packages/CompanionDeviceManager/Android.mk
new file mode 100644
index 0000000..f730356
--- /dev/null
+++ b/packages/CompanionDeviceManager/Android.mk
@@ -0,0 +1,27 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CompanionDeviceManager
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
new file mode 100644
index 0000000..65cac09
--- /dev/null
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2017 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companiondevicemanager">
+
+    <permission
+        android:name="com.android.companiondevicemanager.permission.BIND"
+        android:protectionLevel="signature" />
+
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+    <application
+        android:allowClearUserData="true"
+        android:label="@string/app_label"
+        android:allowBackup="false"
+        android:supportsRtl="true">
+
+        <service
+            android:name=".DeviceDiscoveryService"
+            android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
+            android:exported="true">
+        </service>
+
+        <activity
+            android:name=".DeviceChooserActivity"
+            android:theme="@style/ChooserActivity"
+            android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE">
+            <!--TODO include url scheme filter similar to PrintSpooler -->
+            <intent-filter>
+                <action android:name="android.companiondevice.START_DISCOVERY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/packages/CompanionDeviceManager/MODULE_LICENSE_APACHE2 b/packages/CompanionDeviceManager/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/CompanionDeviceManager/MODULE_LICENSE_APACHE2
diff --git a/packages/CompanionDeviceManager/NOTICE b/packages/CompanionDeviceManager/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/CompanionDeviceManager/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
similarity index 67%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/CompanionDeviceManager/res/drawable/dialog_background.xml
index 807c042..af2c83f 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+    <shape android:shape="rectangle">
+        <corners android:radius="2dp" />
+        <solid android:color="?android:attr/colorBackground" />
+    </shape>
+</inset>
diff --git a/packages/CompanionDeviceManager/res/layout/buttons.xml b/packages/CompanionDeviceManager/res/layout/buttons.xml
new file mode 100644
index 0000000..350a791
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/buttons.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/buttons"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:layout_alignParentBottom="true"
+    android:layout_alignParentEnd="true"
+    android:gravity="end"
+>
+    <Button
+        android:id="@+id/button_cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/cancel"
+        style="@android:style/Widget.Material.Light.Button.Borderless.Colored"
+    />
+    <Button
+        android:id="@+id/button_pair"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/pair"
+        style="@android:style/Widget.Material.Light.Button.Borderless.Colored"
+    />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/device_chooser.xml b/packages/CompanionDeviceManager/res/layout/device_chooser.xml
new file mode 100644
index 0000000..88de33f
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/device_chooser.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_height="400dp"
+    style="@style/ContainerLayout"
+    >
+
+    <include layout="@layout/title" />
+
+    <ListView
+        android:id="@+id/device_list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@+id/title"
+        android:layout_above="@+id/buttons"
+        style="@android:style/Widget.Material.Light.ListView"
+    />
+
+    <include layout="@layout/buttons" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/CompanionDeviceManager/res/layout/device_confirmation.xml
similarity index 63%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/CompanionDeviceManager/res/layout/device_confirmation.xml
index 807c042..7cde41a 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/CompanionDeviceManager/res/layout/device_confirmation.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,7 +14,15 @@
      limitations under the License.
 -->
 
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_height="wrap_content"
+    style="@style/ContainerLayout"
+    >
+
+    <include layout="@layout/title" />
+
+    <include layout="@layout/buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/CompanionDeviceManager/res/layout/title.xml
similarity index 63%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/CompanionDeviceManager/res/layout/title.xml
index 807c042..dfa71e2 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/CompanionDeviceManager/res/layout/title.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,7 +14,12 @@
      limitations under the License.
 -->
 
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/title"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textColor="@android:color/black"
+    style="@*android:style/TextAppearance.Widget.Toolbar.Title"
+/>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/dimens.xml b/packages/CompanionDeviceManager/res/values/dimens.xml
new file mode 100644
index 0000000..da7b0d1
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values/dimens.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <!--  Padding applied on most UI elements  -->
+    <dimen name="padding">12dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
new file mode 100644
index 0000000..469c1fb
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Title of the CompanionDeviceManager application. [CHAR LIMIT=50] -->
+    <string name="app_label">Companion Device Manager</string>
+
+    <!-- Title of the device selection dialog. -->
+    <string name="chooser_title">Pair with &lt;strong&gt;<xliff:g id="app_name" example="Android Wear">%1$s</xliff:g>&lt;/strong&gt; via Bluetooth?</string>
+
+    <!-- Title of the device pairing confirmation dialog. -->
+    <string name="confirmation_title">Pair &lt;strong&gt;<xliff:g id="app_name" example="Android Wear">%1$s</xliff:g>&lt;/strong&gt; with &lt;strong&gt;<xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g>&lt;/strong&gt; via Bluetooth?</string>
+
+    <!-- Label on the pair button in a companion device chooser/confirmation dialog -->
+    <string name="pair">Pair</string>
+
+    <!-- Label on the cancel button in a companion device chooser/confirmation dialog -->
+    <string name="cancel">Cancel</string>
+
+</resources>
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
new file mode 100644
index 0000000..9dced47b
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+    <style name="ContainerLayout">
+        <item name="android:orientation">vertical</item>
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:elevation">16dp</item>
+        <item name="android:background">@drawable/dialog_background</item>
+        <item name="android:paddingTop">18dip</item>
+        <item name="android:paddingStart">20dip</item>
+        <item name="android:paddingEnd">16dip</item>
+        <item name="android:paddingBottom">16dip</item>
+        <item name="android:layout_gravity">center</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/CompanionDeviceManager/res/values/themes.xml
similarity index 61%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/CompanionDeviceManager/res/values/themes.xml
index 807c042..e3fc67c 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/CompanionDeviceManager/res/values/themes.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -15,6 +15,12 @@
 -->
 
 <resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
+
+    <style name="ChooserActivity"
+           parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
+        <item name="*android:windowFixedHeightMajor">100%</item>
+        <item name="*android:windowFixedHeightMinor">100%</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+    </style>
+
 </resources>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
new file mode 100644
index 0000000..8a970da
--- /dev/null
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -0,0 +1,140 @@
+/*
+ * 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.companiondevicemanager;
+
+import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayName;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothDevice;
+import android.companion.CompanionDeviceManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+import android.text.Html;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class DeviceChooserActivity extends Activity {
+
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "DeviceChooserActivity";
+
+    private ListView mDeviceListView;
+    private View mPairButton;
+    private View mCancelButton;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (DEBUG) Log.i(LOG_TAG, "Started with intent " + getIntent());
+
+        if (getService().mDevicesFound.isEmpty()) {
+            Log.e(LOG_TAG, "About to show UI, but no devices to show");
+        }
+
+        if (getService().mRequest.isSingleDevice()) {
+            setContentView(R.layout.device_confirmation);
+            final BluetoothDevice selectedDevice = getService().mDevicesFound.get(0);
+            setTitle(Html.fromHtml(getString(
+                    R.string.confirmation_title,
+                    getCallingAppName(),
+                    getDeviceDisplayName(selectedDevice)), 0));
+            getService().mSelectedDevice = selectedDevice;
+        } else {
+            setContentView(R.layout.device_chooser);
+            setTitle(Html.fromHtml(getString(R.string.chooser_title, getCallingAppName()), 0));
+            mDeviceListView = (ListView) findViewById(R.id.device_list);
+            final DeviceDiscoveryService.DevicesAdapter adapter = getService().mDevicesAdapter;
+            mDeviceListView.setAdapter(adapter);
+            adapter.registerDataSetObserver(new DataSetObserver() {
+                @Override
+                public void onChanged() {
+                    updatePairButtonEnabled();
+                }
+            });
+            mDeviceListView.addFooterView(getProgressBar(), null, false);
+        }
+
+        mPairButton = findViewById(R.id.button_pair);
+        mPairButton.setOnClickListener((view) ->
+                onPairTapped(getService().mSelectedDevice));
+        updatePairButtonEnabled();
+
+        mCancelButton = findViewById(R.id.button_cancel);
+        mCancelButton.setOnClickListener((view) -> {
+            setResult(RESULT_CANCELED);
+            finish();
+        });
+    }
+
+    private CharSequence getCallingAppName() {
+        try {
+            final PackageManager packageManager = getPackageManager();
+            return packageManager.getApplicationLabel(
+                    packageManager.getApplicationInfo(getService().mCallingPackage, 0));
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        final TextView titleView = (TextView) findViewById(R.id.title);
+        final int padding = getPadding(getResources());
+        titleView.setPadding(padding, padding, padding, padding);
+        titleView.setText(title);
+    }
+
+    //TODO put in resources xmls
+    private ProgressBar getProgressBar() {
+        final ProgressBar progressBar = new ProgressBar(this);
+        progressBar.setForegroundGravity(Gravity.CENTER_HORIZONTAL);
+        final int padding = getPadding(getResources());
+        progressBar.setPadding(padding, padding, padding, padding);
+        return progressBar;
+    }
+
+    static int getPadding(Resources r) {
+        return r.getDimensionPixelSize(R.dimen.padding);
+    }
+
+    private void updatePairButtonEnabled() {
+        mPairButton.setEnabled(getService().mSelectedDevice != null);
+    }
+
+    private DeviceDiscoveryService getService() {
+        return DeviceDiscoveryService.sInstance;
+    }
+
+    protected void onPairTapped(BluetoothDevice selectedDevice) {
+        setResult(RESULT_OK,
+                new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice));
+        finish();
+    }
+
+    private void toast(String msg) {
+        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+    }
+}
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
new file mode 100644
index 0000000..ccbee2a
--- /dev/null
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companiondevicemanager;
+
+import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayName;
+import static android.companion.BluetoothLEDeviceFilter.nullsafe;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.companion.AssociationRequest;
+import android.companion.BluetoothDeviceFilterUtils;
+import android.companion.BluetoothLEDeviceFilter;
+import android.companion.ICompanionDeviceManagerService;
+import android.companion.IOnAssociateCallback;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class DeviceDiscoveryService extends Service {
+
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "DeviceDiscoveryService";
+
+    static DeviceDiscoveryService sInstance;
+
+    private BluetoothAdapter mBluetoothAdapter;
+    private BluetoothLEDeviceFilter mFilter;
+    private ScanFilter mScanFilter;
+    private ScanSettings mDefaultScanSettings = new ScanSettings.Builder().build();
+    AssociationRequest<?> mRequest;
+    List<BluetoothDevice> mDevicesFound;
+    BluetoothDevice mSelectedDevice;
+    DevicesAdapter mDevicesAdapter;
+    IOnAssociateCallback mCallback;
+    String mCallingPackage;
+
+    private final ICompanionDeviceManagerService mBinder =
+            new ICompanionDeviceManagerService.Stub() {
+        @Override
+        public void startDiscovery(AssociationRequest request,
+                IOnAssociateCallback callback,
+                String callingPackage) throws RemoteException {
+            if (DEBUG) {
+                Log.i(LOG_TAG,
+                        "startDiscovery() called with: filter = [" + request + "], callback = ["
+                                + callback + "]");
+            }
+            mCallback = callback;
+            mCallingPackage = callingPackage;
+            DeviceDiscoveryService.this.startDiscovery(request);
+        }
+    };
+
+    private final ScanCallback mBLEScanCallback = new ScanCallback() {
+        @Override
+        public void onScanResult(int callbackType, ScanResult result) {
+            final BluetoothDevice device = result.getDevice();
+            if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST) {
+                onDeviceLost(device);
+            } else {
+                onDeviceFound(device);
+            }
+        }
+    };
+
+    private BluetoothLeScanner mBLEScanner;
+
+    private BroadcastReceiver mBluetoothDeviceFoundBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final BluetoothDevice device = intent.getParcelableExtra(
+                    BluetoothDevice.EXTRA_DEVICE);
+            if (!mFilter.matches(device)) return; // ignore device
+
+            if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
+                onDeviceFound(device);
+            } else {
+                onDeviceLost(device);
+            }
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (DEBUG) Log.i(LOG_TAG, "onBind(" + intent + ")");
+        return mBinder.asBinder();
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        if (DEBUG) Log.i(LOG_TAG, "onCreate()");
+
+        mBluetoothAdapter = getSystemService(BluetoothManager.class).getAdapter();
+        mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
+
+        mDevicesFound = new ArrayList<>();
+        mDevicesAdapter = new DevicesAdapter();
+
+        sInstance = this;
+    }
+
+    private void startDiscovery(AssociationRequest<?> request) {
+        //TODO support other protocols as well
+        mRequest = request;
+        mFilter = nullsafe((BluetoothLEDeviceFilter) request.getDeviceFilter());
+        mScanFilter = mFilter.getScanFilter();
+
+        reset();
+
+        final IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
+        intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
+
+        registerReceiver(mBluetoothDeviceFoundBroadcastReceiver, intentFilter);
+        mBluetoothAdapter.startDiscovery();
+
+        mBLEScanner.startScan(
+                Collections.singletonList(mScanFilter), mDefaultScanSettings, mBLEScanCallback);
+    }
+
+    private void reset() {
+        mDevicesFound.clear();
+        mSelectedDevice = null;
+        mDevicesAdapter.notifyDataSetChanged();
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        stopScan();
+        return super.onUnbind(intent);
+    }
+
+    private void stopScan() {
+        if (DEBUG) Log.i(LOG_TAG, "stopScan() called");
+        mBluetoothAdapter.cancelDiscovery();
+        mBLEScanner.stopScan(mBLEScanCallback);
+        unregisterReceiver(mBluetoothDeviceFoundBroadcastReceiver);
+        stopSelf();
+    }
+
+    private void onDeviceFound(BluetoothDevice device) {
+        if (mDevicesFound.contains(device)) {
+            return;
+        }
+
+        if (DEBUG) {
+            Log.i(LOG_TAG, "Considering device " + getDeviceDisplayName(device));
+        }
+
+        if (!mFilter.matches(device)) {
+            return;
+        }
+
+        if (DEBUG) {
+            Log.i(LOG_TAG, "Found device " + getDeviceDisplayName(device));
+        }
+        if (mDevicesFound.isEmpty()) {
+            onReadyToShowUI();
+        }
+        mDevicesFound.add(device);
+        mDevicesAdapter.notifyDataSetChanged();
+    }
+
+    //TODO also, on timeout -> call onFailure
+    private void onReadyToShowUI() {
+        try {
+            mCallback.onSuccess(PendingIntent.getActivity(
+                    this, 0,
+                    new Intent(this, DeviceChooserActivity.class),
+                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT
+                            | PendingIntent.FLAG_IMMUTABLE));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void onDeviceLost(BluetoothDevice device) {
+        mDevicesFound.remove(device);
+        mDevicesAdapter.notifyDataSetChanged();
+        if (DEBUG) {
+            Log.i(LOG_TAG, "Lost device " + getDeviceDisplayName(device));
+        }
+    }
+
+    class DevicesAdapter extends ArrayAdapter<BluetoothDevice> {
+        private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth);
+
+        private Drawable icon(int drawableRes) {
+            Drawable icon = getResources().getDrawable(drawableRes, null);
+            icon.setTint(Color.DKGRAY);
+            return icon;
+        }
+
+        public DevicesAdapter() {
+            super(DeviceDiscoveryService.this, 0, mDevicesFound);
+        }
+
+        @Override
+        public View getView(
+                int position,
+                @Nullable View convertView,
+                @NonNull ViewGroup parent) {
+            TextView view = convertView instanceof TextView
+                    ? (TextView) convertView
+                    : newView();
+            bind(view, getItem(position));
+            return view;
+        }
+
+        private void bind(TextView textView, BluetoothDevice device) {
+            textView.setText(getDeviceDisplayName(device));
+            textView.setBackgroundColor(
+                    device.equals(mSelectedDevice)
+                            ? Color.GRAY
+                            : Color.TRANSPARENT);
+            textView.setOnClickListener((view) -> {
+                mSelectedDevice = device;
+                notifyDataSetChanged();
+            });
+        }
+
+        //TODO move to a layout file
+        private TextView newView() {
+            final TextView textView = new TextView(DeviceDiscoveryService.this);
+            textView.setTextColor(Color.BLACK);
+            final int padding = DeviceChooserActivity.getPadding(getResources());
+            textView.setPadding(padding, padding, padding, padding);
+            textView.setCompoundDrawablesWithIntrinsicBounds(
+                    BLUETOOTH_ICON, null, null, null);
+            textView.setCompoundDrawablePadding(padding);
+            return textView;
+        }
+    }
+}
diff --git a/packages/Keyguard/res/values-bn/strings.xml b/packages/Keyguard/res/values-bn/strings.xml
index 1a2a8dd..64c01bb 100644
--- a/packages/Keyguard/res/values-bn/strings.xml
+++ b/packages/Keyguard/res/values-bn/strings.xml
@@ -47,8 +47,8 @@
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"সিম কার্ডটি PUK কোড দিয়ে লক করা আছে৷"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"সিম কার্ড আনলক করা হচ্ছে…"</string>
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"পিন অঞ্চল"</string>
-    <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM পিন অঞ্চল"</string>
-    <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK অঞ্চল"</string>
+    <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"সিম পিন অঞ্চল"</string>
+    <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"সিম PUK অঞ্চল"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g> এ পরবর্তী অ্যালার্ম সেট করা হয়েছে"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"মুছুন"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
@@ -59,11 +59,11 @@
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"আপনার প্যাটার্ন আঁকুন"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"সিম পিন লিখুন"</string>
-    <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" এর জন্য SIM পিন লিখুন"</string>
+    <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" এর জন্য সিম পিন লিখুন"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"পিন লিখুন"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"পাসওয়ার্ড লিখুন"</string>
     <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"সিম এখন অক্ষম করা হয়েছে৷ অবিরত থাকতে PUK কোডটি লিখুন৷ বিশদ বিবরণের জন্য ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
-    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" এখন অক্ষম করা হয়েছে৷ চালিয়ে যেতে PUK কোড লিখুন৷ বিস্তারিত জানার জন্য ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"সিম \"<xliff:g id="CARRIER">%1$s</xliff:g>\" এখন অক্ষম করা হয়েছে৷ চালিয়ে যেতে PUK কোড লিখুন৷ বিস্তারিত জানার জন্য ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"কাঙ্ক্ষিত পিন কোড লিখুন"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"কাঙ্ক্ষিত পিন কোড নিশ্চিত করুন"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"সিম কার্ড আনলক করা হচ্ছে…"</string>
@@ -91,13 +91,13 @@
     <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_password_wrong_pin_code_pukked" msgid="30531039455764924">"ভুল সিম পিন কোড, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার ক্যারিয়ারের সাথে যোগাযোগ করতে হবে৷"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
-      <item quantity="one">ভুল SIM পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
-      <item quantity="other">ভুল SIM পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
+      <item quantity="one">ভুল সিম পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
+      <item quantity="other">ভুল সিম পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIMটি ব্যবহারের অযোগ্য৷ আপনার ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
-      <item quantity="one">ভুল SIM PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
-      <item quantity="other">ভুল SIM PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
+      <item quantity="one">ভুল সিম PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
+      <item quantity="other">ভুল সিম PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"সিম পিন ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"সিম PUK ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index b98a253..0fb7416 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -58,7 +58,7 @@
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Forkert pinkode"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn dit mønster"</string>
-    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM-kort"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Indtast SIM-pinkoden for \"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"Angiv adgangskode"</string>
@@ -105,13 +105,13 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen dækning."</string>
     <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Skift indtastningsmetode"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Flytilstand"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Du skal indtaste et mønster efter genstart af enheden"</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Du skal angive et mønster efter genstart af enheden"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Der skal indtaste en pinkode efter genstart af enheden"</string>
     <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Du skal indtaste en adgangskode efter genstart af enheden"</string>
     <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Der kræves et mønster som ekstra beskyttelse"</string>
     <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Der kræves en pinkode som ekstra beskyttelse"</string>
     <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Der kræves en adgangskode som ekstra beskyttelse"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Du skal indtaste et mønster, når du skifter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Du skal angive et mønster, når du skifter profil"</string>
     <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Du skal indtaste en pinkode, når du skifter profil"</string>
     <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Du skal indtaste en adgangskode, når du skifter profil"</string>
     <string name="kg_prompt_reason_device_admin" msgid="5838877342219587193">"Enhedsadministratoren har låst enheden"</string>
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/SettingsLib/res/color/batterymeter_bolt_color.xml
similarity index 69%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/SettingsLib/res/color/batterymeter_bolt_color.xml
index 807c042..34de548 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/SettingsLib/res/color/batterymeter_bolt_color.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/SettingsLib/res/color/batterymeter_charge_color.xml
similarity index 69%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/SettingsLib/res/color/batterymeter_charge_color.xml
index 807c042..15944c3 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/SettingsLib/res/color/batterymeter_charge_color.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/SettingsLib/res/color/batterymeter_frame_color.xml
similarity index 69%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/SettingsLib/res/color/batterymeter_frame_color.xml
index 807c042..34de548 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/SettingsLib/res/color/batterymeter_frame_color.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
similarity index 69%
rename from core/res/res/values-ldrtl/dimens.xml
rename to packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
index 807c042..c8a80ac 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.24" android:color="?android:attr/colorBackground" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
similarity index 69%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
index 807c042..8dcfdbb 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.47" android:color="?android:attr/colorBackground" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
similarity index 69%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
index 807c042..34de548 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/values-ldrtl/dimens.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
similarity index 69%
copy from core/res/res/values-ldrtl/dimens.xml
copy to packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
index 807c042..15944c3 100644
--- a/core/res/res/values-ldrtl/dimens.xml
+++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-    <item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
-    <item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index 01ba2cd..b40bfd4 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"শুধুমাত্র DRM সামগ্রীর জন্য HDCP চেক করা ব্যবহার করুন"</item>
     <item msgid="45075631231212732">"সর্বদা HDCP পরীক্ষণ ব্যবহার করুন"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
     <item msgid="8895532488906185219">"৪৪.১ kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"মোনো"</item>
     <item msgid="8883739882299884241">"স্টিরিও"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"অডিও গুণমানের জন্য অপ্টিমাইজ করা হয়েছে (৯৯০kbps/৯০৯kbps)"</item>
+    <item msgid="2921767058740704969">"সন্তুলিত গুণমানের অডিও এবং সংযোগ (660kbps/606kbps)"</item>
+    <item msgid="8860982705384396512">"সংযোগের গুণমানের জন্য অপটিমাইজ করা হয়েছে (৩৩০kbps/৩০৩kbps)"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"অডিও গুণমানের জন্য অপ্টিমাইজ করা হয়েছে"</item>
+    <item msgid="4327143584633311908">"সন্তুলিত গুণমানের অডিও এবং সংযোগ"</item>
+    <item msgid="4681409244565426925">"সংযোগের গুণমানের জন্য অপটিমাইজ করা হয়েছে"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"বন্ধ আছে"</item>
     <item msgid="1593289376502312923">"৬৪K"</item>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 8350bb7..08f7227 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -53,7 +53,7 @@
     <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"পরিচিতি শেয়ার করার কাজে ব্যবহার করুন"</string>
     <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ইন্টারনেট সংযোগ শেয়ার করা হচ্ছে"</string>
     <string name="bluetooth_profile_map" msgid="5465271250454324383">"বার্তা অ্যাক্সেস"</string>
-    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM -এর অ্যাক্সেস"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"সিম -এর অ্যাক্সেস"</string>
     <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিওতে সংযুক্ত রয়েছে"</string>
     <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিওতে সংযুক্ত"</string>
     <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল স্থানান্তর সার্ভারের সঙ্গে সংযুক্ত"</string>
@@ -65,7 +65,7 @@
     <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ডিভাইসের সাথে স্থানীয় ইন্টারনেট সংযোগ ভাগ করছে"</string>
     <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ইন্টারনেট অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"মানচিত্রের জন্য ব্যবহার করুন"</string>
-    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM -এর অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"সিম -এর অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"মিডিয়া অডিওয়ের জন্য ব্যবহার করুন"</string>
     <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ফোন অডিওয়ের জন্য ব্যবহার করুন"</string>
     <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ফাইল স্থানান্তরের জন্য ব্যবহার করুন"</string>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index f27f265..1c3d3bf 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -111,9 +111,9 @@
     <item msgid="8883739882299884241">"Stereo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="7158319962230727476">"Optimizirano za kvalitet zvuka (990kbps/909kbps)"</item>
+    <item msgid="7158319962230727476">"Optimizirano za kvalitet zvuka (990 kbps/909 kbps)"</item>
     <item msgid="2921767058740704969">"Uravnotežen kvalitet zvuka i veze (660kbps/606kbps)"</item>
-    <item msgid="8860982705384396512">"Optimizirano za kvalitet veze (330kbps/303kbps)"</item>
+    <item msgid="8860982705384396512">"Optimizirano za kvalitet veze (330 kbps/303 kbps)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
     <item msgid="6398189564246596868">"Optimizirano za kvalitet zvuka"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 2d36397..8071c83 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -202,7 +202,7 @@
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Vil du ophæve adgangen til USB-fejlfinding for alle computere, du tidligere har godkendt?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Vil du tillade udviklingsindstillinger?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens applikationer går ned eller ikke fungerer korrekt."</string>
-    <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Kontrollér apps via USB"</string>
+    <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificer apps via USB"</string>
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollér apps, der er installeret via ADB/ADT, for skadelig adfærd."</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiverer funktionen til absolut lydstyrke via Bluetooth i tilfælde af problemer med lydstyrken på eksterne enheder, f.eks. uacceptabel høj lyd eller manglende kontrol."</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 3493c08..d5155c9 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"Utilizar comprobación de HDCP solo para contenido DRM"</item>
     <item msgid="45075631231212732">"Utilizar siempre comprobación de HDCP"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"Usar preferencia del sistema (predeter.)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"Usar preferencia del sistema (predeter.)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"Usar preferencia del sistema (predeter.)"</item>
     <item msgid="8895532488906185219">"44,1 kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"Mono"</item>
     <item msgid="8883739882299884241">"Estéreo"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"Optimizado para la calidad del audio (990 kbps/909 kbps)"</item>
+    <item msgid="2921767058740704969">"Equilibrar la calidad del audio y de la conexión (660/606&amp;nbsp;kbps)"</item>
+    <item msgid="8860982705384396512">"Optimizado para la calidad de la conexión (330 kbps/303 kbps)"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"Se ha optimizado para la calidad del audio"</item>
+    <item msgid="4327143584633311908">"Equilibrar la calidad del audio y la de la conexión"</item>
+    <item msgid="4681409244565426925">"Se ha optimizado para la calidad de la conexión"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"No"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index 4148a4e..e4bcf482 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -111,9 +111,9 @@
     <item msgid="8883739882299884241">"Estereoa"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="7158319962230727476">"Audioaren kalitatea areagotzeko optimizatua (990 kb/s / 909 kb/s)"</item>
-    <item msgid="2921767058740704969">"Orekatu audioaren eta konexioaren kalitateak (660 kbps / 606 kbps)"</item>
-    <item msgid="8860982705384396512">"Konexioaren kalitatea areagotzeko optimizatua (330 kb/s / 303 kb/s)"</item>
+    <item msgid="7158319962230727476">"Audioaren kalitatea areagotzeko optimizatua (990 Kb/s / 909 Kb/s)"</item>
+    <item msgid="2921767058740704969">"Audioaren eta konexioaren kalitate orekatua (660 Kb/s / 606 Kb/s)"</item>
+    <item msgid="8860982705384396512">"Konexioaren kalitatea areagotzeko optimizatua (330 Kb/s / 303 Kb/s)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
     <item msgid="6398189564246596868">"Audioaren kalitatea areagotzeko optimizatua"</item>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index e871198..6eb4321 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"ફક્ત DRM સામગ્રી માટે HDCP તપાસનો ઉપયોગ કરો"</item>
     <item msgid="45075631231212732">"હંમેશા HDCP તપાસનો ઉપયોગ કરો"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
     <item msgid="8895532488906185219">"44.1 kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"મૉનો"</item>
     <item msgid="8883739882299884241">"સ્ટીરિઓ"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"ઑડિઓની ગુણવત્તા (990 kbps/909 kbps) માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+    <item msgid="2921767058740704969">"સંતુલિત ઑડિઓ અને કનેક્શનની ગુણવત્તા (660kbps/606kbps)"</item>
+    <item msgid="8860982705384396512">"કનેક્શનની ગુણવત્તા (330 kbps/303 kbps) માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"ઑડિઓની ગુણવત્તા માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+    <item msgid="4327143584633311908">"સંતુલિત ઑડિઓ અને કનેક્શનની ગુણવત્તા"</item>
+    <item msgid="4681409244565426925">"કનેક્શનની ગુણવત્તા માટે ઓપ્ટિમાઇઝ કર્યું"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"બંધ"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 88f6e78..8925f32 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -111,12 +111,12 @@
     <item msgid="8883739882299884241">"Ստերեո"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="7158319962230727476">"Օպտիմալացված ձայնի որակ համար (990 կբ/վ / 909 կբ/վ)"</item>
+    <item msgid="7158319962230727476">"Օպտիմալացված ձայնի որակի համար (990 կբ/վ / 909 կբ/վ)"</item>
     <item msgid="2921767058740704969">"Ձայնի և կապի հավասարակշռված որակ (660 կբ/վ / 606 կբ/վ)"</item>
     <item msgid="8860982705384396512">"Օպտիմալացված կապի որակի համար (330 կբ/վ / 303 կբ/վ)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="6398189564246596868">"Օպտիմալացված ձայնի որակ համար"</item>
+    <item msgid="6398189564246596868">"Օպտիմալացված ձայնի որակի համար"</item>
     <item msgid="4327143584633311908">"Ձայնի և կապի հավասարակշռված որակ"</item>
     <item msgid="4681409244565426925">"Օպտիմալացված կապի որակի համար"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 12d61fe..186b79c 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -140,10 +140,10 @@
     <string name="choose_profile" msgid="8229363046053568878">"Pilih Profil"</string>
     <string name="category_personal" msgid="1299663247844969448">"Pribadi"</string>
     <string name="category_work" msgid="8699184680584175622">"Kantor"</string>
-    <string name="development_settings_title" msgid="215179176067683667">"Opsi pengembang"</string>
-    <string name="development_settings_enable" msgid="542530994778109538">"Aktifkan opsi pengembang"</string>
+    <string name="development_settings_title" msgid="215179176067683667">"Opsi developer"</string>
+    <string name="development_settings_enable" msgid="542530994778109538">"Aktifkan opsi developer"</string>
     <string name="development_settings_summary" msgid="1815795401632854041">"Menyetel opsi untuk pengembangan apl"</string>
-    <string name="development_settings_not_available" msgid="4308569041701535607">"Opsi pengembang tidak tersedia untuk pengguna ini"</string>
+    <string name="development_settings_not_available" msgid="4308569041701535607">"Opsi developer tidak tersedia untuk pengguna ini"</string>
     <string name="vpn_settings_not_available" msgid="956841430176985598">"Setelan VPN tidak tersedia untuk pengguna ini"</string>
     <string name="tethering_settings_not_available" msgid="6765770438438291012">"Setelan Penambatan tidak tersedia untuk pengguna ini"</string>
     <string name="apn_settings_not_available" msgid="7873729032165324000">"Setelan Nama Titik Akses tidak tersedia untuk pengguna ini"</string>
diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml
index 73851a4..c729b42 100644
--- a/packages/SettingsLib/res/values-kn/arrays.xml
+++ b/packages/SettingsLib/res/values-kn/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"DRM ವಿಷಯಗಳಿಗೆ ಮಾತ್ರ HDCP ಪರೀಕ್ಷಿಸುವಿಕೆಯನ್ನು ಬಳಸು"</item>
     <item msgid="45075631231212732">"HDCP ಪರಿಶೀಲನೆಯನ್ನು ಯಾವಾಗಲೂ ಬಳಸು"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
     <item msgid="8895532488906185219">"44.1 kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"ಮೊನೊ"</item>
     <item msgid="8883739882299884241">"ಸ್ಟೀರಿಯೊ"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"ಆಡಿಯೋ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ (990kbps/909kbps) ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗಿದೆ"</item>
+    <item msgid="2921767058740704969">"ಸಂತುಲಿತ ಆಡಿಯೊ ಮತ್ತು ಸಂಪರ್ಕದ ಗುಣಮಟ್ಟ (660kbps/606kbps)"</item>
+    <item msgid="8860982705384396512">"ಸಂಪರ್ಕದ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ (330kbps/303kbps) ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗಿದೆ"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"ಆಡಿಯೊ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ ಆಪ್ಟಿಮೈಸ್‌ ಮಾಡಲಾಗಿದೆ"</item>
+    <item msgid="4327143584633311908">"ಸಂತುಲಿತ ಆಡಿಯೊ ಮತ್ತು ಸಂಪರ್ಕದ ಗುಣಮಟ್ಟ"</item>
+    <item msgid="4681409244565426925">"ಸಂಪರ್ಕ ಗುಣಮಟ್ಟಕ್ಕಾಗಿ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗಿದೆ"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ಆಫ್"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml
index f00ebe5..4d1a685 100644
--- a/packages/SettingsLib/res/values-ky/arrays.xml
+++ b/packages/SettingsLib/res/values-ky/arrays.xml
@@ -111,14 +111,14 @@
     <item msgid="8883739882299884241">"Стерео"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="7158319962230727476">"Аудио сапаты үчүн оптималдаштырылды (990кб/сек./909кб/сек.)"</item>
+    <item msgid="7158319962230727476">"Аудионун сапатын оптималдаштыруу (990кб/сек./909кб/сек.)"</item>
     <item msgid="2921767058740704969">"Теңделген аудио жана туташуу сапаты (660кб/сек./606кб/сек.)"</item>
-    <item msgid="8860982705384396512">"Туташуу сапаты үчүн оптималдаштырылды (330кб/сек./303кб/сек.)"</item>
+    <item msgid="8860982705384396512">"Туташуунун сапатын оптималдаштыруу (330кб/сек./303кб/сек.)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="6398189564246596868">"Аудио сапаты үчүн оптималдаштырылды"</item>
+    <item msgid="6398189564246596868">"Аудионун сапатын оптималдаштыруу"</item>
     <item msgid="4327143584633311908">"Теңделген аудио жана туташуу сапаты"</item>
-    <item msgid="4681409244565426925">"Туташуу сапаты үчүн оптималдаштырылды"</item>
+    <item msgid="4681409244565426925">"Туташуунун сапатын оптималдаштыруу"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Өчүк"</item>
diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml
index bb05b8c..e79a567 100644
--- a/packages/SettingsLib/res/values-ml/arrays.xml
+++ b/packages/SettingsLib/res/values-ml/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"DRM ഉള്ളടക്കത്തിനുമാത്രമായി HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
     <item msgid="45075631231212732">"എല്ലായ്‌പ്പോഴും HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
     <item msgid="8895532488906185219">"44.1 kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"മോണോ"</item>
     <item msgid="8883739882299884241">"സ്റ്റീരിയോ"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"ശബ്‌ദനിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു (990kbps/909kbps)"</item>
+    <item msgid="2921767058740704969">"സന്തുലിതമായ ‌ഓഡിയോ/കണക്ഷൻ നിലവാരം (660kbps/606kbps)"</item>
+    <item msgid="8860982705384396512">"കണക്ഷൻ നിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു (330kbps/303kbps)"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"ശബ്‌ദനിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു"</item>
+    <item msgid="4327143584633311908">"സന്തുലിതമായ ‌ഓഡിയോ/കണക്ഷൻ നിലവാരം"</item>
+    <item msgid="4681409244565426925">"കണക്ഷൻ നിലവാരമുയർത്താൻ ഒപ്‌റ്റിമൈസ് ചെയ്‌തു"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ഓഫ്"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index 751b7be..e83b1f9 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"केवळ DRM सामग्रीसाठी HDCP तपासणी वापरा"</item>
     <item msgid="45075631231212732">"नेहमी HDCP तपासणी वापरा"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"प्रणाली निवड वापरा (डीफॉल्ट)"</item>
     <item msgid="8895532488906185219">"44.1 kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"मोनो"</item>
     <item msgid="8883739882299884241">"स्टिरिओ"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"ऑडिओ गुणवत्ता (990kbps/909kbps) साठी ऑप्टिमाइझ केली"</item>
+    <item msgid="2921767058740704969">"संतुलित ऑडिओ आणि कनेक्शन गुणवत्ता (660kbps/606kbps)"</item>
+    <item msgid="8860982705384396512">"कनेक्शन गुणवत्ता (330kbps/303kbps) साठी ऑप्टिमाइझ केली"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"ऑडिओ गुणवत्तेसाठी ऑप्टिमाइझ केले"</item>
+    <item msgid="4327143584633311908">"संतुलित ऑडिओ आणि कनेक्शन गुणवत्ता"</item>
+    <item msgid="4681409244565426925">"कनेक्शन गुणवत्तेसाठी ऑप्टिमाइझ केले"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"बंद"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index 46a758e..cee130b 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"DRM सामग्रीको लागि मात्र HDCP जाँचको प्रयोग गर्नुहोस्"</item>
     <item msgid="45075631231212732">"सधैँ HDCP जाँच प्रयोग गर्नुहोस्"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"प्रणालीको चयन प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
     <item msgid="8895532488906185219">"४४.१ kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"मोनो"</item>
     <item msgid="8883739882299884241">"स्टेरियो"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"अडियोको गुणस्तर सुधार्न अनुकूलन गरिएको (990kbps/909kbps)"</item>
+    <item msgid="2921767058740704969">"सन्तुलित अडियो र जडान गुणस्तर (६६०kbps/६०६kbps)"</item>
+    <item msgid="8860982705384396512">"जडानको गुणस्तर सुधार्न अनुकूलन गरिएको (330kbps/303kbps)"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"अडियोको गुणस्तर सुधार्न अनुकूलन गरिएको"</item>
+    <item msgid="4327143584633311908">"सन्तुलित अडियो र जडान गुणस्तर"</item>
+    <item msgid="4681409244565426925">"जडानको गुणस्तर सुधार्न अनुकूलन गरिएको"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"निष्क्रिय गर्नुहोस्"</item>
     <item msgid="1593289376502312923">"६४के"</item>
diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml
index 1f94398..7ad1d17 100644
--- a/packages/SettingsLib/res/values-ur/arrays.xml
+++ b/packages/SettingsLib/res/values-ur/arrays.xml
@@ -58,14 +58,22 @@
     <item msgid="3878793616631049349">"‏HDCP چیکنگ صرف DRM مواد کیلئے استعمال کریں"</item>
     <item msgid="45075631231212732">"‏ہمیشہ HDCP چیکنگ استعمال کریں"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:2 (686685526567131661) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (8910200421843557332) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:4 (8434403964359457768) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:5 (6751080638867012696) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:2 (6839647709301342559) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (2279916056363477395) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (6641171061200063516) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:5 (7950781694447359344) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="7065842274271279580">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+    <item msgid="7539690996561263909">"SBC"</item>
+    <item msgid="686685526567131661">"AAC"</item>
+    <item msgid="8910200421843557332">"aptX"</item>
+    <item msgid="8434403964359457768">"aptX HD"</item>
+    <item msgid="6751080638867012696">"LDAC"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="5062108632402595000">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+    <item msgid="6898329690939802290">"SBC"</item>
+    <item msgid="6839647709301342559">"AAC"</item>
+    <item msgid="2279916056363477395">"aptX"</item>
+    <item msgid="6641171061200063516">"aptX HD"</item>
+    <item msgid="7950781694447359344">"LDAC"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="3093023430402746802">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
     <item msgid="8895532488906185219">"44.1 kHz"</item>
@@ -102,10 +110,16 @@
     <item msgid="8900559293912978337">"مونو"</item>
     <item msgid="8883739882299884241">"اسٹیریو"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (7158319962230727476) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (8860982705384396512) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (6398189564246596868) -->
-    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (4681409244565426925) -->
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+    <item msgid="7158319962230727476">"‏آڈیو کے معیار کیلئے بہتر بنایا گيا (990kbps/909kbps)"</item>
+    <item msgid="2921767058740704969">"‏متوازن آڈیو اور کنکشن کا معیار (660kbps/606kbps)"</item>
+    <item msgid="8860982705384396512">"‏کنکشن کے معیار کیلئے بہتر بنایا گيا (330kbps/303kbps)"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
+    <item msgid="6398189564246596868">"آڈیو کے معیار کیلئے بہتر بنایا گيا"</item>
+    <item msgid="4327143584633311908">"متوازن آڈیو اور کنکشن کا معیار"</item>
+    <item msgid="4681409244565426925">"کنکشن کے معیار کیلئے بہتر بنایا گيا"</item>
+  </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"آف"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 7bbca5e..eb64b3a 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -520,4 +520,37 @@
         <item>7</item>
     </integer-array>
 
+    <!-- BatteryMeterView parameters -->
+    <array name="batterymeter_color_levels">
+        <item>15</item>
+        <item>100</item>
+    </array>
+    <array name="batterymeter_color_values">
+        <item>@*android:color/battery_saver_mode_color</item>
+        <item>@android:color/white</item>
+    </array>
+    <array name="batterymeter_bolt_points">
+        <item>73</item> <item>0</item>
+        <item>392</item><item>0</item>
+        <item>201</item><item>259</item>
+        <item>442</item><item>259</item>
+        <item>4</item>  <item>703</item>
+        <item>157</item><item>334</item>
+        <item>0</item>  <item>334</item>
+    </array>
+    <array name="batterymeter_plus_points">
+        <item>3</item><item>0</item>
+        <item>5</item><item>0</item>
+        <item>5</item><item>3</item>
+        <item>8</item><item>3</item>
+        <item>8</item><item>5</item>
+        <item>5</item><item>5</item>
+        <item>5</item><item>8</item>
+        <item>3</item><item>8</item>
+        <item>3</item><item>5</item>
+        <item>0</item><item>5</item>
+        <item>0</item><item>3</item>
+        <item>3</item><item>3</item>
+    </array>
+
 </resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 2e8b30f..aa36617 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -57,4 +57,15 @@
     <dimen name="drawer_width">300dp</dimen>
     <dimen name="drawer_item_top_bottom_margin">4dp</dimen>
     <dimen name="drawer_spacer_height">32dp</dimen>
+
+    <dimen name="battery_height">14.5dp</dimen>
+    <dimen name="battery_width">9.5dp</dimen>
+
+    <!-- Margin on the right side of the system icon group on Keyguard. -->
+    <fraction name="battery_button_height_fraction">10.5%</fraction>
+
+    <!-- Fraction value to smooth the edges of the battery icon. The path will be inset by this
+         fraction of a pixel.-->
+    <fraction name="battery_subpixel_smoothing_left">0%</fraction>
+    <fraction name="battery_subpixel_smoothing_right">0%</fraction>
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 0129632..5475b32 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -900,4 +900,7 @@
     <string name="retail_demo_reset_next">Next</string>
     <!-- Title for carrier demo mode factory reset confirmation dialog. [CHAR LIMIT=40] -->
     <string name="retail_demo_reset_title">Password required</string>
+
+    <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
+    <string name="battery_meter_very_low_overlay_symbol">!</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 13bbc33..4b0ab59 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -94,16 +94,27 @@
 
     private static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
 
+    // Default dismiss control for smart suggestions.
+    private static final String DEFAULT_SMART_DISMISS_CONTROL = "0,10";
+
     private final Context mContext;
     private final List<SuggestionCategory> mSuggestionList;
     private final ArrayMap<Pair<String, String>, Tile> mAddCache = new ArrayMap<>();
     private final SharedPreferences mSharedPrefs;
+    private final String mSmartDismissControl;
 
-    public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
+
+    public SuggestionParser(
+        Context context, SharedPreferences sharedPrefs, int orderXml, String smartDismissControl) {
         mContext = context;
         mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
                 .parse(orderXml);
         mSharedPrefs = sharedPrefs;
+        mSmartDismissControl = smartDismissControl;
+    }
+
+    public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
+       this(context, sharedPrefs, orderXml, DEFAULT_SMART_DISMISS_CONTROL);
     }
 
     @VisibleForTesting
@@ -111,26 +122,35 @@
         mContext = context;
         mSuggestionList = new ArrayList<SuggestionCategory>();
         mSharedPrefs = sharedPrefs;
+        mSmartDismissControl = DEFAULT_SMART_DISMISS_CONTROL;
         Log.wtf(TAG, "Only use this constructor for testing");
     }
 
     public List<Tile> getSuggestions() {
+        return getSuggestions(false);
+    }
+
+    public List<Tile> getSuggestions(boolean isSmartSuggestionEnabled) {
         List<Tile> suggestions = new ArrayList<>();
         final int N = mSuggestionList.size();
         for (int i = 0; i < N; i++) {
-            readSuggestions(mSuggestionList.get(i), suggestions);
+            readSuggestions(mSuggestionList.get(i), suggestions, isSmartSuggestionEnabled);
         }
         return suggestions;
     }
 
+    public boolean dismissSuggestion(Tile suggestion) {
+        return dismissSuggestion(suggestion, false);
+    }
+
     /**
      * Dismisses a suggestion, returns true if the suggestion has no more dismisses left and should
      * be disabled.
      */
-    public boolean dismissSuggestion(Tile suggestion) {
+    public boolean dismissSuggestion(Tile suggestion, boolean isSmartSuggestionEnabled) {
         String keyBase = suggestion.intent.getComponent().flattenToShortString();
         int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
-        String dismissControl = suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+        String dismissControl = getDismissControl(suggestion, isSmartSuggestionEnabled);
         if (dismissControl == null || parseDismissString(dismissControl).length == index) {
             return true;
         }
@@ -141,20 +161,23 @@
     }
 
     @VisibleForTesting
-    public void filterSuggestions(List<Tile> suggestions, int countBefore) {
+    public void filterSuggestions(
+        List<Tile> suggestions, int countBefore, boolean isSmartSuggestionEnabled) {
         for (int i = countBefore; i < suggestions.size(); i++) {
             if (!isAvailable(suggestions.get(i)) ||
                     !isSupported(suggestions.get(i)) ||
                     !satisifesRequiredUserType(suggestions.get(i)) ||
                     !satisfiesRequiredAccount(suggestions.get(i)) ||
                     !satisfiesConnectivity(suggestions.get(i)) ||
-                    isDismissed(suggestions.get(i))) {
+                    isDismissed(suggestions.get(i), isSmartSuggestionEnabled)) {
                 suggestions.remove(i--);
             }
         }
     }
 
-    private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) {
+    @VisibleForTesting
+    void readSuggestions(
+        SuggestionCategory category, List<Tile> suggestions, boolean isSmartSuggestionEnabled) {
         int countBefore = suggestions.size();
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(category.category);
@@ -163,7 +186,7 @@
         }
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
                 mAddCache, null, suggestions, true, false);
-        filterSuggestions(suggestions, countBefore);
+        filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
         if (!category.multiple && suggestions.size() > (countBefore + 1)) {
             // If there are too many, remove them all and only re-add the one with the highest
             // priority.
@@ -288,12 +311,11 @@
         Settings.Secure.putInt(mContext.getContentResolver(), name, 1);
     }
 
-    private boolean isDismissed(Tile suggestion) {
-        Object dismissObj = suggestion.metaData.get(META_DATA_DISMISS_CONTROL);
-        if (dismissObj == null) {
+    private boolean isDismissed(Tile suggestion, boolean isSmartSuggestionEnabled) {
+        String dismissControl = getDismissControl(suggestion, isSmartSuggestionEnabled);
+        if (dismissControl == null) {
             return false;
         }
-        String dismissControl = String.valueOf(dismissObj);
         String keyBase = suggestion.intent.getComponent().flattenToShortString();
         if (!mSharedPrefs.contains(keyBase + SETUP_TIME)) {
             mSharedPrefs.edit()
@@ -333,7 +355,16 @@
         return dismisses;
     }
 
-    private static class SuggestionCategory {
+    private String getDismissControl(Tile suggestion, boolean isSmartSuggestionEnabled) {
+        if (isSmartSuggestionEnabled) {
+            return mSmartDismissControl;
+        } else {
+            return suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+        }
+    }
+
+    @VisibleForTesting
+    static class SuggestionCategory {
         public String category;
         public String pkg;
         public boolean multiple;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index ae6ada2a..11e2a71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -6,8 +6,8 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
 import android.content.pm.Signature;
+import android.content.pm.UserInfo;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapper.java b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapper.java
new file mode 100644
index 0000000..caa7929
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapper.java
@@ -0,0 +1,126 @@
+/*
+ * 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.settingslib.applications;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+
+import java.util.List;
+
+/**
+ * This interface replicates a subset of the android.content.pm.PackageManager (PM). The interface
+ * exists so that we can use a thin wrapper around the PM in production code and a mock in tests.
+ * We cannot directly mock or shadow the PM, because some of the methods we rely on are newer than
+ * the API version supported by Robolectric.
+ */
+public interface PackageManagerWrapper {
+
+    /**
+     * Returns the real {@code PackageManager} object.
+     */
+    PackageManager getPackageManager();
+
+    /**
+     * Calls {@code PackageManager.getInstalledApplicationsAsUser()}.
+     *
+     * @see android.content.pm.PackageManager#getInstalledApplicationsAsUser
+     */
+    List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId);
+
+    /**
+     * Calls {@code PackageManager.hasSystemFeature()}.
+     *
+     * @see android.content.pm.PackageManager#hasSystemFeature
+     */
+    boolean hasSystemFeature(String name);
+
+    /**
+     * Calls {@code PackageManager.queryIntentActivitiesAsUser()}.
+     *
+     * @see android.content.pm.PackageManager#queryIntentActivitiesAsUser
+     */
+    List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId);
+
+    /**
+     * Calls {@code PackageManager.getInstallReason()}.
+     *
+     * @see android.content.pm.PackageManager#getInstallReason
+     */
+    int getInstallReason(String packageName, UserHandle user);
+
+    /**
+     * Calls {@code PackageManager.getApplicationInfoAsUser}
+     */
+    ApplicationInfo getApplicationInfoAsUser(String packageName, int i, int userId)
+            throws PackageManager.NameNotFoundException;
+
+    /**
+     * Calls {@code PackageManager.setDefaultBrowserPackageNameAsUser}
+     */
+    boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId);
+
+    /**
+     * Calls {@code PackageManager.getDefaultBrowserPackageNameAsUser}
+     */
+    String getDefaultBrowserPackageNameAsUser(int userId);
+
+    /**
+     * Calls {@code PackageManager.getHomeActivities}
+     */
+    ComponentName getHomeActivities(List<ResolveInfo> homeActivities);
+
+    /**
+     * Calls {@code PackageManager.queryIntentServicesAsUser}
+     */
+    List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int i, int user);
+
+    /**
+     * Calls {@code PackageManager.replacePreferredActivity}
+     */
+    void replacePreferredActivity(IntentFilter homeFilter, int matchCategoryEmpty,
+            ComponentName[] componentNames, ComponentName component);
+
+    /**
+     * Gets information about a particular package from the package manager.
+     * @param packageName The name of the package we would like information about.
+     * @param i additional options flags. see javadoc for {@link PackageManager#getPackageInfo(String, int)}
+     * @return The PackageInfo for the requested package
+     * @throws NameNotFoundException
+     */
+    PackageInfo getPackageInfo(String packageName, int i) throws NameNotFoundException;
+
+    /**
+     * Retrieves the icon associated with this particular set of ApplicationInfo
+     * @param info The ApplicationInfo to retrieve the icon for
+     * @return The icon as a drawable.
+     */
+    Drawable getUserBadgedIcon(ApplicationInfo info);
+
+    /**
+     * Retrieves the label associated with the particular set of ApplicationInfo
+     * @param app The ApplicationInfo to retrieve the label for
+     * @return the label as a CharSequence
+     */
+    CharSequence loadLabel(ApplicationInfo app);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapperImpl.java b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapperImpl.java
new file mode 100644
index 0000000..9b2cd7c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapperImpl.java
@@ -0,0 +1,116 @@
+/*
+ * 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.settingslib.applications;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+
+import java.util.List;
+
+/**
+ * A thin wrapper class that simplifies testing by putting a mockable layer between the application
+ * and the PackageManager. This class only provides access to the minimum number of functions from
+ * the PackageManager needed for DeletionHelper to work.
+ */
+public class PackageManagerWrapperImpl implements PackageManagerWrapper {
+
+    private final PackageManager mPm;
+
+    public PackageManagerWrapperImpl(PackageManager pm) {
+        mPm = pm;
+    }
+
+    @Override
+    public PackageManager getPackageManager() {
+        return mPm;
+    }
+
+    @Override
+    public List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) {
+        return mPm.getInstalledApplicationsAsUser(flags, userId);
+    }
+
+    @Override
+    public boolean hasSystemFeature(String name) {
+        return mPm.hasSystemFeature(name);
+    }
+
+    @Override
+    public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
+        return mPm.queryIntentActivitiesAsUser(intent, flags, userId);
+    }
+
+    @Override
+    public int getInstallReason(String packageName, UserHandle user) {
+        return mPm.getInstallReason(packageName, user);
+    }
+
+    @Override
+    public ApplicationInfo getApplicationInfoAsUser(String packageName, int i, int userId)
+            throws PackageManager.NameNotFoundException {
+        return mPm.getApplicationInfoAsUser(packageName, i, userId);
+    }
+
+    @Override
+    public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
+        return mPm.setDefaultBrowserPackageNameAsUser(packageName, userId);
+    }
+
+    @Override
+    public String getDefaultBrowserPackageNameAsUser(int userId) {
+        return mPm.getDefaultBrowserPackageNameAsUser(userId);
+    }
+
+    @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> homeActivities) {
+        return mPm.getHomeActivities(homeActivities);
+    }
+
+    @Override
+    public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int i, int user) {
+        return mPm.queryIntentServicesAsUser(intent, i, user);
+    }
+
+    @Override
+    public void replacePreferredActivity(IntentFilter homeFilter, int matchCategoryEmpty,
+            ComponentName[] componentNames, ComponentName component) {
+        mPm.replacePreferredActivity(homeFilter, matchCategoryEmpty, componentNames, component);
+    }
+
+    @Override
+    public PackageInfo getPackageInfo(String packageName, int i) throws NameNotFoundException {
+        return mPm.getPackageInfo(packageName, i);
+    }
+
+    @Override
+    public Drawable getUserBadgedIcon(ApplicationInfo info) {
+        return mPm.getUserBadgedIcon(mPm.loadUnbadgedItemIcon(info, info),
+                new UserHandle(UserHandle.getUserId(info.uid)));
+    }
+
+    @Override
+    public CharSequence loadLabel(ApplicationInfo app) {
+        return app.loadLabel(mPm);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
new file mode 100644
index 0000000..acb0650
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
@@ -0,0 +1,117 @@
+/*
+ * 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.settingslib.applications;
+
+import android.app.usage.StorageStats;
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.os.UserHandle;
+
+/**
+ * StorageStatsSource wraps the StorageStatsManager for testability purposes.
+ */
+public class StorageStatsSource {
+    private StorageStatsManager mStorageStatsManager;
+
+    public StorageStatsSource(Context context) {
+        mStorageStatsManager = context.getSystemService(StorageStatsManager.class);
+    }
+
+    public StorageStatsSource.ExternalStorageStats getExternalStorageStats(String volumeUuid, UserHandle user) {
+        return new StorageStatsSource.ExternalStorageStats(
+                mStorageStatsManager.queryExternalStatsForUser(volumeUuid, user));
+    }
+
+    public StorageStatsSource.AppStorageStats getStatsForUid(String volumeUuid, int uid) {
+        return new StorageStatsSource.AppStorageStatsImpl(mStorageStatsManager.queryStatsForUid(volumeUuid, uid));
+    }
+
+    /**
+     * Static class that provides methods for querying the amount of external storage available as
+     * well as breaking it up into several media types.
+     */
+    public static class ExternalStorageStats {
+        public long totalBytes;
+        public long audioBytes;
+        public long videoBytes;
+        public long imageBytes;
+
+        /**
+         * Convenience method for testing.
+         */
+        public ExternalStorageStats(long totalBytes, long audioBytes, long videoBytes,
+                long imageBytes) {
+            this.totalBytes = totalBytes;
+            this.audioBytes = audioBytes;
+            this.videoBytes = videoBytes;
+            this.imageBytes = imageBytes;
+        }
+
+        /**
+         * Creates an ExternalStorageStats from the system version of ExternalStorageStats. They are
+         * identical other than the utility method created for test purposes.
+         * @param stats The stats to copy to wrap.
+         */
+        public ExternalStorageStats(android.app.usage.ExternalStorageStats stats) {
+            totalBytes = stats.getTotalBytes();
+            audioBytes = stats.getAudioBytes();
+            videoBytes = stats.getVideoBytes();
+            imageBytes = stats.getImageBytes();
+        }
+    }
+
+    /**
+     * Interface that exists to simplify testing. The platform {@link StorageStats} is too new and
+     * robolectric cannot see it. It simply wraps a StorageStats object and forwards method calls
+     * to the real object
+     */
+    public interface AppStorageStats {
+        long getCodeBytes();
+        long getDataBytes();
+        long getCacheBytes();
+        long getTotalBytes();
+    }
+
+    /**
+     * Simple implementation of AppStorageStats that will allow you to query the StorageStats object
+     * passed in for storage information about an app.
+     */
+    public static class AppStorageStatsImpl implements
+            StorageStatsSource.AppStorageStats {
+        private StorageStats mStats;
+
+        public AppStorageStatsImpl(StorageStats stats) {
+            mStats = stats;
+        }
+
+        public long getCodeBytes() {
+            return mStats.getCodeBytes();
+        }
+
+        public long getDataBytes() {
+            return mStats.getDataBytes();
+        }
+
+        public long getCacheBytes() {
+            return mStats.getCacheBytes();
+        }
+
+        public long getTotalBytes() {
+            return mStats.getCacheBytes() + mStats.getCodeBytes() + mStats.getDataBytes();
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index 32478a7..7f469b5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -34,6 +34,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 
 import com.android.settingslib.R;
@@ -273,6 +274,11 @@
         super.invalidateSelf();
     }
 
+    @Override
+    public ConstantState getConstantState() {
+        return new BitmapDrawable(mBitmap).getConstantState();
+    }
+
     /**
      * This 'bakes' the current state of this icon into a bitmap and removes/recycles the source
      * bitmap/drawable. Use this when no more changes will be made and an intrinsic size is set.
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 7e3f67b..d6bde81 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -36,7 +36,6 @@
     public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
     public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
     public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
-    public static final String CATEGORY_SYSTEM_INPUT = "com.android.settings.category.ia.input";
     public static final String CATEGORY_SYSTEM_LANGUAGE =
             "com.android.settings.category.ia.language";
     public static final String CATEGORY_SYSTEM_DEVELOPMENT =
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
new file mode 100755
index 0000000..fd2e7ca
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -0,0 +1,465 @@
+/*
+ * 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.settingslib.graph;
+
+import android.animation.ArgbEvaluator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.provider.Settings;
+import com.android.settingslib.R;
+import com.android.settingslib.Utils;
+
+public class BatteryMeterDrawableBase extends Drawable {
+
+    private static final float ASPECT_RATIO = 9.5f / 14.5f;
+    public static final String TAG = BatteryMeterDrawableBase.class.getSimpleName();
+
+    protected final Context mContext;
+
+    private int mLevel = -1;
+    private boolean mPluggedIn;
+    private boolean mPowerSaveEnabled;
+    private boolean mShowPercent;
+
+    private static final boolean SINGLE_DIGIT_PERCENT = false;
+
+    private static final int FULL = 96;
+
+    private static final float BOLT_LEVEL_THRESHOLD = 0.3f;  // opaque bolt below this fraction
+
+    private final int[] mColors;
+    private final int mIntrinsicWidth;
+    private final int mIntrinsicHeight;
+
+    private float mButtonHeightFraction;
+    private float mSubpixelSmoothingLeft;
+    private float mSubpixelSmoothingRight;
+    private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
+            mPlusPaint;
+    private float mTextHeight, mWarningTextHeight;
+    private int mIconTint = Color.WHITE;
+    private float mOldDarkIntensity = 0f;
+
+    private int mHeight;
+    private int mWidth;
+    private String mWarningString;
+    private final int mCriticalLevel;
+    private int mChargeColor;
+    private final float[] mBoltPoints;
+    private final Path mBoltPath = new Path();
+    private final float[] mPlusPoints;
+    private final Path mPlusPath = new Path();
+
+    private final RectF mFrame = new RectF();
+    private final RectF mButtonFrame = new RectF();
+    private final RectF mBoltFrame = new RectF();
+    private final RectF mPlusFrame = new RectF();
+
+    private final Path mShapePath = new Path();
+    private final Path mClipPath = new Path();
+    private final Path mTextPath = new Path();
+
+    private int mDarkModeBackgroundColor;
+    private int mDarkModeFillColor;
+
+    private int mLightModeBackgroundColor;
+    private int mLightModeFillColor;
+
+    public BatteryMeterDrawableBase(Context context, int frameColor) {
+        mContext = context;
+        final Resources res = context.getResources();
+        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
+        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
+
+        final int N = levels.length();
+        mColors = new int[2 * N];
+        for (int i = 0; i < N; i++) {
+            mColors[2 * i] = levels.getInt(i, 0);
+            mColors[2 * i + 1] = colors.getColor(i, 0);
+        }
+        levels.recycle();
+        colors.recycle();
+
+        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+        mCriticalLevel = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+        mButtonHeightFraction = context.getResources().getFraction(
+                R.fraction.battery_button_height_fraction, 1, 1);
+        mSubpixelSmoothingLeft = context.getResources().getFraction(
+                R.fraction.battery_subpixel_smoothing_left, 1, 1);
+        mSubpixelSmoothingRight = context.getResources().getFraction(
+                R.fraction.battery_subpixel_smoothing_right, 1, 1);
+
+        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mFramePaint.setColor(frameColor);
+        mFramePaint.setDither(true);
+        mFramePaint.setStrokeWidth(0);
+        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBatteryPaint.setDither(true);
+        mBatteryPaint.setStrokeWidth(0);
+        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+        mTextPaint.setTypeface(font);
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        font = Typeface.create("sans-serif", Typeface.BOLD);
+        mWarningTextPaint.setTypeface(font);
+        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+        if (mColors.length > 1) {
+            mWarningTextPaint.setColor(mColors[1]);
+        }
+
+        mChargeColor = Utils.getDefaultColor(mContext, R.color.batterymeter_charge_color);
+
+        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBoltPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_bolt_color));
+        mBoltPoints = loadPoints(res, R.array.batterymeter_bolt_points);
+
+        mPlusPaint = new Paint(mBoltPaint);
+        mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);
+
+        mDarkModeBackgroundColor =
+                Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_background);
+        mDarkModeFillColor =
+                Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_fill);
+        mLightModeBackgroundColor =
+                Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_background);
+        mLightModeFillColor =
+                Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_fill);
+
+        mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
+        mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mIntrinsicHeight;
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mIntrinsicWidth;
+    }
+
+    public void setShowPercent(boolean show) {
+        mShowPercent = show;
+        postInvalidate();
+    }
+
+    public void setPluggedIn(boolean val) {
+        mPluggedIn = val;
+        postInvalidate();
+    }
+
+    public void setBatteryLevel(int val) {
+        mLevel = val;
+        postInvalidate();
+    }
+
+    public void setPowerSave(boolean val) {
+        mPowerSaveEnabled = val;
+        postInvalidate();
+    }
+
+    // an approximation of View.postInvalidate()
+    protected void postInvalidate() {
+        unscheduleSelf(this::invalidateSelf);
+        scheduleSelf(this::invalidateSelf, 0);
+    }
+
+    private static float[] loadPoints(Resources res, int pointArrayRes) {
+        final int[] pts = res.getIntArray(pointArrayRes);
+        int maxX = 0, maxY = 0;
+        for (int i = 0; i < pts.length; i += 2) {
+            maxX = Math.max(maxX, pts[i]);
+            maxY = Math.max(maxY, pts[i + 1]);
+        }
+        final float[] ptsF = new float[pts.length];
+        for (int i = 0; i < pts.length; i += 2) {
+            ptsF[i] = (float) pts[i] / maxX;
+            ptsF[i + 1] = (float) pts[i + 1] / maxY;
+        }
+        return ptsF;
+    }
+
+    @Override
+    public void setBounds(int left, int top, int right, int bottom) {
+        super.setBounds(left, top, right, bottom);
+        mHeight = bottom - top;
+        mWidth = right - left;
+        mWarningTextPaint.setTextSize(mHeight * 0.75f);
+        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+    }
+
+    private int getColorForLevel(int percent) {
+        // If we are in power save mode, always use the normal color.
+        if (mPowerSaveEnabled) {
+            return mColors[mColors.length - 1];
+        }
+        int thresh, color = 0;
+        for (int i = 0; i < mColors.length; i += 2) {
+            thresh = mColors[i];
+            color = mColors[i + 1];
+            if (percent <= thresh) {
+
+                // Respect tinting for "normal" level
+                if (i == mColors.length - 2) {
+                    return mIconTint;
+                } else {
+                    return color;
+                }
+            }
+        }
+        return color;
+    }
+
+    public void setDarkIntensity(float darkIntensity) {
+        if (darkIntensity == mOldDarkIntensity) {
+            return;
+        }
+        int backgroundColor = getBackgroundColor(darkIntensity);
+        int fillColor = getFillColor(darkIntensity);
+        setColors(fillColor, backgroundColor);
+        mOldDarkIntensity = darkIntensity;
+    }
+
+    public void setColors(int fillColor, int backgroundColor) {
+        mIconTint = fillColor;
+        mFramePaint.setColor(backgroundColor);
+        mBoltPaint.setColor(fillColor);
+        mChargeColor = fillColor;
+        invalidateSelf();
+    }
+
+    private int getBackgroundColor(float darkIntensity) {
+        return getColorForDarkIntensity(
+                darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
+    }
+
+    private int getFillColor(float darkIntensity) {
+        return getColorForDarkIntensity(
+                darkIntensity, mLightModeFillColor, mDarkModeFillColor);
+    }
+
+    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        final int level = mLevel;
+
+        if (level == -1) return;
+
+        float drawFrac = (float) level / 100f;
+        final int height = mHeight;
+        final int width = (int) (ASPECT_RATIO * mHeight);
+        int px = (mWidth - width) / 2;
+
+        final int buttonHeight = (int) (height * mButtonHeightFraction);
+
+        mFrame.set(0, 0, width, height);
+        mFrame.offset(px, 0);
+
+        // button-frame: area above the battery body
+        mButtonFrame.set(
+                mFrame.left + Math.round(width * 0.25f),
+                mFrame.top,
+                mFrame.right - Math.round(width * 0.25f),
+                mFrame.top + buttonHeight);
+
+        mButtonFrame.top += mSubpixelSmoothingLeft;
+        mButtonFrame.left += mSubpixelSmoothingLeft;
+        mButtonFrame.right -= mSubpixelSmoothingRight;
+
+        // frame: battery body area
+        mFrame.top += buttonHeight;
+        mFrame.left += mSubpixelSmoothingLeft;
+        mFrame.top += mSubpixelSmoothingLeft;
+        mFrame.right -= mSubpixelSmoothingRight;
+        mFrame.bottom -= mSubpixelSmoothingRight;
+
+        // set the battery charging color
+        mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
+
+        if (level >= FULL) {
+            drawFrac = 1f;
+        } else if (level <= mCriticalLevel) {
+            drawFrac = 0f;
+        }
+
+        final float levelTop = drawFrac == 1f ? mButtonFrame.top
+                : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
+
+        // define the battery shape
+        mShapePath.reset();
+        mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
+        mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
+        mShapePath.lineTo(mButtonFrame.right, mFrame.top);
+        mShapePath.lineTo(mFrame.right, mFrame.top);
+        mShapePath.lineTo(mFrame.right, mFrame.bottom);
+        mShapePath.lineTo(mFrame.left, mFrame.bottom);
+        mShapePath.lineTo(mFrame.left, mFrame.top);
+        mShapePath.lineTo(mButtonFrame.left, mFrame.top);
+        mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+
+        if (mPluggedIn) {
+            // define the bolt shape
+            final float bl = mFrame.left + mFrame.width() / 4f;
+            final float bt = mFrame.top + mFrame.height() / 6f;
+            final float br = mFrame.right - mFrame.width() / 4f;
+            final float bb = mFrame.bottom - mFrame.height() / 10f;
+            if (mBoltFrame.left != bl || mBoltFrame.top != bt
+                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+                mBoltFrame.set(bl, bt, br, bb);
+                mBoltPath.reset();
+                mBoltPath.moveTo(
+                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+                for (int i = 2; i < mBoltPoints.length; i += 2) {
+                    mBoltPath.lineTo(
+                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+                }
+                mBoltPath.lineTo(
+                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+            }
+
+            float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
+            boltPct = Math.min(Math.max(boltPct, 0), 1);
+            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+                // draw the bolt if opaque
+                c.drawPath(mBoltPath, mBoltPaint);
+            } else {
+                // otherwise cut the bolt out of the overall shape
+                mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
+            }
+        } else if (mPowerSaveEnabled) {
+            // define the plus shape
+            final float pw = mFrame.width() * 2 / 3;
+            final float pl = mFrame.left + (mFrame.width() - pw) / 2;
+            final float pt = mFrame.top + (mFrame.height() - pw) / 2;
+            final float pr = mFrame.right - (mFrame.width() - pw) / 2;
+            final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
+            if (mPlusFrame.left != pl || mPlusFrame.top != pt
+                    || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
+                mPlusFrame.set(pl, pt, pr, pb);
+                mPlusPath.reset();
+                mPlusPath.moveTo(
+                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+                for (int i = 2; i < mPlusPoints.length; i += 2) {
+                    mPlusPath.lineTo(
+                            mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
+                            mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
+                }
+                mPlusPath.lineTo(
+                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+            }
+
+            float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
+            boltPct = Math.min(Math.max(boltPct, 0), 1);
+            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+                // draw the bolt if opaque
+                c.drawPath(mPlusPath, mPlusPaint);
+            } else {
+                // otherwise cut the bolt out of the overall shape
+                mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
+            }
+        }
+
+        // compute percentage text
+        boolean pctOpaque = false;
+        float pctX = 0, pctY = 0;
+        String pctText = null;
+        if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
+            mTextPaint.setColor(getColorForLevel(level));
+            mTextPaint.setTextSize(height *
+                    (SINGLE_DIGIT_PERCENT ? 0.75f
+                            : (mLevel == 100 ? 0.38f : 0.5f)));
+            mTextHeight = -mTextPaint.getFontMetrics().ascent;
+            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level / 10) : level);
+            pctX = mWidth * 0.5f;
+            pctY = (mHeight + mTextHeight) * 0.47f;
+            pctOpaque = levelTop > pctY;
+            if (!pctOpaque) {
+                mTextPath.reset();
+                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+                // cut the percentage text out of the overall shape
+                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
+            }
+        }
+
+        // draw the battery shape background
+        c.drawPath(mShapePath, mFramePaint);
+
+        // draw the battery shape, clipped to charging level
+        mFrame.top = levelTop;
+        mClipPath.reset();
+        mClipPath.addRect(mFrame, Path.Direction.CCW);
+        mShapePath.op(mClipPath, Path.Op.INTERSECT);
+        c.drawPath(mShapePath, mBatteryPaint);
+
+        if (!mPluggedIn && !mPowerSaveEnabled) {
+            if (level <= mCriticalLevel) {
+                // draw the warning text
+                final float x = mWidth * 0.5f;
+                final float y = (mHeight + mWarningTextHeight) * 0.48f;
+                c.drawText(mWarningString, x, y, mWarningTextPaint);
+            } else if (pctOpaque) {
+                // draw the percentage text
+                c.drawText(pctText, pctX, pctY, mTextPaint);
+            }
+        }
+    }
+
+    // Some stuff required by Drawable.
+    @Override
+    public void setAlpha(int alpha) {
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+        mFramePaint.setColorFilter(colorFilter);
+        mBatteryPaint.setColorFilter(colorFilter);
+        mWarningTextPaint.setColorFilter(colorFilter);
+        mBoltPaint.setColorFilter(colorFilter);
+        mPlusPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    public int getOpacity() {
+        return 0;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 06ea445..82e69d8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -222,21 +222,21 @@
         if (isActive() && !other.isActive()) return -1;
         if (!isActive() && other.isActive()) return 1;
 
-        // Higher scores go before lower scores
-        if (mRankingScore != other.mRankingScore) {
-            return (mRankingScore > other.mRankingScore) ? -1 : 1;
-        }
-
         // Reachable one goes before unreachable one.
         if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
         if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
 
-        // Configured one goes before unconfigured one.
+        // Configured (saved) one goes before unconfigured one.
         if (networkId != WifiConfiguration.INVALID_NETWORK_ID
                 && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
         if (networkId == WifiConfiguration.INVALID_NETWORK_ID
                 && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
 
+        // Higher scores go before lower scores
+        if (mRankingScore != other.mRankingScore) {
+            return (mRankingScore > other.mRankingScore) ? -1 : 1;
+        }
+
         // Sort by signal strength, bucketed by level
         int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS)
                 - WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index c617994..0ec16ae2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -41,7 +41,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.provider.Settings;
-import android.support.annotation.WorkerThread;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -211,7 +210,7 @@
 
         mNetworkScoreManager = networkScoreManager;
 
-        mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(mWorkHandler) {
+        mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(mMainHandler) {
             @Override
             public void networkCacheUpdated(List<ScoredNetwork> networks) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -282,12 +281,7 @@
      * then forceUpdate() must be called to populate getAccessPoints().
      */
     public void startTracking() {
-        mWorkHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                registerScoreCache();
-            }
-        });
+        registerScoreCache();
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.NETWORK_SCORING_UI_ENABLED),
@@ -305,7 +299,6 @@
         }
     }
 
-    @WorkerThread
     private void registerScoreCache() {
         mNetworkScoreManager.registerNetworkScoreCache(
                 NetworkKey.TYPE_WIFI,
@@ -341,20 +334,17 @@
         }
         pauseScanning();
 
-        mWorkHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                unregisterAndClearScoreCache();
-            }
-        });
+        unregisterAndClearScoreCache();
+
         mContext.getContentResolver().unregisterContentObserver(mObserver);
     }
 
-    @WorkerThread
     private void unregisterAndClearScoreCache() {
-        mRequestedScores.clear();
         mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, mScoreCache);
         mScoreCache.clearScores();
+
+        // Clear the scores on the work handler to avoid concurrent modification exceptions
+        mWorkHandler.post(() -> mRequestedScores.clear());
     }
 
     /**
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
new file mode 100644
index 0000000..4de2c12
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -0,0 +1,71 @@
+package com.android.settingslib.graph;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.settingslib.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryMeterDrawableBaseTest {
+    private Context mContext;
+    private Resources mResources;
+    private BatteryMeterDrawableBase mBatteryDrawable;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mResources = mContext.getResources();
+        mBatteryDrawable = new BatteryMeterDrawableBase(mContext, 0);
+    }
+
+    @Test
+    public void testGetIntrinsicSize() {
+        assertThat(mBatteryDrawable.getIntrinsicWidth()).
+                isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_width));
+        assertThat(mBatteryDrawable.getIntrinsicHeight()).
+                isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_height));
+    }
+
+    @Test
+    public void testDrawNothingBeforeOnBatteryLevelChanged() {
+        final Canvas canvas = mock(Canvas.class);
+        mBatteryDrawable.draw(canvas);
+        verify(canvas, never()).drawPath(any(), any());
+        verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+    }
+
+    @Test
+    public void testDrawingForTypicalValues() {
+        final Canvas canvas = mock(Canvas.class);
+        final int levels[] = { 0, 1, 5, 10, 25, 50, 75, 90, 95, 99, 100 };
+        final boolean bools[] = { false, true };
+        for (int l : levels) {
+            for (boolean plugged : bools) {
+                for (boolean saver : bools) {
+                    for (boolean percent : bools) {
+                        mBatteryDrawable.setBatteryLevel(l);
+                        mBatteryDrawable.setPowerSave(saver);
+                        mBatteryDrawable.setPluggedIn(plugged);
+                        mBatteryDrawable.setShowPercent(percent);
+                        mBatteryDrawable.draw(canvas);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 08736c7..0f220aa 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -72,7 +72,7 @@
 public class WifiTrackerTest {
 
     private static final String TAG = "WifiTrackerTest";
-    private static final int LATCH_TIMEOUT = 2000;
+    private static final int LATCH_TIMEOUT = 4000;
 
     private static final String SSID_1 = "ssid1";
     private static final String BSSID_1 = "00:00:00:00:00:00";
@@ -226,7 +226,7 @@
 
         mAccessPointsChangedLatch = new CountDownLatch(1);
         sendScanResultsAndProcess(tracker);
-        mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+        assertTrue(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
 
         return tracker;
     }
@@ -242,7 +242,8 @@
                     true,
                     mockWifiManager,
                     mockConnectivityManager,
-                        mockNetworkScoreManager, mMainLooper
+                    mockNetworkScoreManager,
+                    mMainLooper
                 );
 
         return tracker;
@@ -257,7 +258,7 @@
                 latch.countDown();
             }
         });
-        latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+        assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
     private void sendScanResultsAndProcess(WifiTracker tracker) throws InterruptedException {
@@ -265,7 +266,8 @@
         Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
         tracker.mReceiver.onReceive(mContext, i);
 
-        mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+        assertTrue("Latch timed out",
+                mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
     private void updateScores() {
@@ -348,7 +350,7 @@
         // Test unregister
         tracker.stopTracking();
 
-        latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+        assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
         verify(mockNetworkScoreManager)
                 .unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
     }
@@ -359,12 +361,15 @@
         WifiTracker tracker =  createTrackerAndInjectInitialScanResults();
 
         tracker.stopTracking();
+        android.util.Log.d("WifiTrackerTest", "Clearing previously captured requested keys");
         mRequestedKeys.clear();
 
-        mRequestScoresLatch = new CountDownLatch(2);
+        mRequestScoresLatch = new CountDownLatch(1);
         startTracking(tracker);
-        mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+        assertTrue("Latch timed out",
+                mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
 
+        android.util.Log.d("WifiTrackerTest", "requested keys: " + mRequestedKeys);
         assertTrue(mRequestedKeys.contains(NETWORK_KEY_1));
         assertTrue(mRequestedKeys.contains(NETWORK_KEY_2));
     }
@@ -379,6 +384,8 @@
     }
 
     private void updateScoresAndWaitForAccessPointsChangedCallback() throws InterruptedException {
+        // Updating scores can happen together or one after the other, so the latch countdown is set
+        // to 2.
         mAccessPointsChangedLatch = new CountDownLatch(2);
         updateScores();
         mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
@@ -462,6 +469,8 @@
 
     @Test
     public void scoresShouldBeRequestedForNewScanResultOnly()  throws InterruptedException {
+        // Scores can be requested together or serially depending on how the scan results are
+        // processed.
         mRequestScoresLatch = new CountDownLatch(2);
         WifiTracker tracker = createTrackerAndInjectInitialScanResults();
         mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
@@ -484,9 +493,24 @@
 
         mRequestScoresLatch = new CountDownLatch(1);
         sendScanResultsAndProcess(tracker);
-        mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+        assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
 
         assertEquals(1, mRequestedKeys.size());
         assertTrue(mRequestedKeys.contains(new NetworkKey(new WifiKey('"' + ssid + '"', bssid))));
     }
+
+    @Test
+    public void scoreCacheAndListenerShouldBeUnregisteredWhenStopTrackingIsCalled() throws Exception
+    {
+        WifiTracker tracker =  createTrackerAndInjectInitialScanResults();
+        WifiNetworkScoreCache cache = mScoreCacheCaptor.getValue();
+
+        tracker.stopTracking();
+        verify(mockNetworkScoreManager).unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, cache);
+
+        // Verify listener is unregistered so updating a score does not throw an error by posting
+        // a message to the dead work handler
+        mWorkerThread.quit();
+        updateScores();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index 7a89884a..596d614 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -43,6 +43,12 @@
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src)
 
+LOCAL_JAR_EXCLUDE_FILES := none
+
+LOCAL_RESOURCE_DIR := \
+    $(LOCAL_PATH)/res
+
+
 include frameworks/base/packages/SettingsLib/common.mk
 
 include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
new file mode 100644
index 0000000..1eeafba
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<optional-steps>
+    <step category="com.android.settings.suggested.category.LOCK_SCREEN" />
+    <step category="com.android.settings.suggested.category.EMAIL" />
+    <step category="com.android.settings.suggested.category.PARTNER_ACCOUNT"
+        multiple="true" />
+    <step category="com.android.settings.suggested.category.HOTWORD" />
+    <step category="com.android.settings.suggested.category.DEFAULT"
+        multiple="true" />
+    <step category="com.android.settings.suggested.category.SETTINGS_ONLY"
+        multiple="true" />
+</optional-steps>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingLibRobolectricTestRunner.java
new file mode 100644
index 0000000..11c925e
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingLibRobolectricTestRunner.java
@@ -0,0 +1,48 @@
+/*
+ * 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.settingslib;
+
+import org.junit.runners.model.InitializationError;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.manifest.AndroidManifest;
+import org.robolectric.res.Fs;
+import org.robolectric.res.ResourcePath;
+
+import java.util.List;
+
+public class SettingLibRobolectricTestRunner extends RobolectricTestRunner {
+
+    public SettingLibRobolectricTestRunner(Class<?> testClass) throws InitializationError {
+        super(testClass);
+    }
+
+    @Override
+    protected AndroidManifest getAppManifest(Config config) {
+        // Using the manifest file's relative path, we can figure out the application directory.
+        final String appRoot = "frameworks/base/packages/SettingsLib";
+        final String manifestPath = appRoot + "/AndroidManifest.xml";
+        final String resDir = appRoot + "/tests/robotests/res";
+        final String assetsDir = appRoot + config.assetDir();
+
+        final AndroidManifest manifest = new AndroidManifest(Fs.fileFromPath(manifestPath),
+                Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir));
+
+        manifest.setPackageName("com.android.settingslib");
+        return manifest;
+    }
+
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
new file mode 100644
index 0000000..7729dec
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.settingslib;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.drawer.TileUtilsTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SuggestionParserTest {
+
+    @Mock
+    private PackageManager mPackageManager;
+    private Context mContext;
+    private SuggestionParser mSuggestionParser;
+    private SuggestionParser.SuggestionCategory mSuggestioCategory;
+    private List<Tile> mSuggestionsBeforeDismiss;
+    private List<Tile> mSuggestionsAfterDismiss;
+    private SharedPreferences mPrefs;
+    private Tile mSuggestion;
+    private List<ResolveInfo> mInfo;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+        mSuggestion = new Tile();
+        mSuggestion.intent = new Intent("action");
+        mSuggestion.intent.setComponent(new ComponentName("pkg", "cls"));
+        mSuggestion.metaData = new Bundle();
+        mSuggestionParser = new SuggestionParser(
+            mContext, mPrefs, R.xml.suggestion_ordering, "0,0");
+        mSuggestioCategory = new SuggestionParser.SuggestionCategory();
+        mSuggestioCategory.category = "category1";
+        mSuggestioCategory.multiple = true;
+        mInfo = new ArrayList<>();
+        ResolveInfo info1 = TileUtilsTest.newInfo(true, "category1");
+        info1.activityInfo.packageName = "pkg";
+        ResolveInfo info2 = TileUtilsTest.newInfo(true, "category1");
+        info2.activityInfo.packageName = "pkg2";
+        mInfo.add(info1);
+        mInfo.add(info2);
+        when(mPackageManager.queryIntentActivitiesAsUser(
+            any(Intent.class), anyInt(), anyInt())).thenReturn(mInfo);
+    }
+
+    @Test
+    public void testDismissSuggestion_withoutSmartSuggestion() {
+        assertThat(mSuggestionParser.dismissSuggestion(mSuggestion, false)).isTrue();
+    }
+
+    @Test
+    public void testDismissSuggestion_withSmartSuggestion() {
+        assertThat(mSuggestionParser.dismissSuggestion(mSuggestion, true)).isFalse();
+    }
+
+    @Test
+    public void testGetSuggestions_withoutSmartSuggestions() {
+        readAndDismissSuggestion(false);
+        mSuggestionParser.readSuggestions(mSuggestioCategory, mSuggestionsAfterDismiss, false);
+        assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
+        assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(1);
+        assertThat(mSuggestionsBeforeDismiss.get(1)).isEqualTo(mSuggestionsAfterDismiss.get(0));
+    }
+
+    @Test
+    public void testGetSuggestions_withSmartSuggestions() {
+        readAndDismissSuggestion(true);
+        assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
+        assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(2);
+        assertThat(mSuggestionsBeforeDismiss).isEqualTo(mSuggestionsAfterDismiss);
+    }
+
+    private void readAndDismissSuggestion(boolean isSmartSuggestionEnabled) {
+        mSuggestionsBeforeDismiss = new ArrayList<Tile>();
+        mSuggestionsAfterDismiss = new ArrayList<Tile>();
+        mSuggestionParser.readSuggestions(
+            mSuggestioCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
+        if (mSuggestionParser.dismissSuggestion(
+            mSuggestionsBeforeDismiss.get(0), isSmartSuggestionEnabled)) {
+            mInfo.remove(0);
+        }
+        mSuggestionParser.readSuggestions(
+            mSuggestioCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java
new file mode 100644
index 0000000..a21390a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.settingslib.drawable;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.android.settingslib.R;
+import com.android.settingslib.SettingLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UserIconDrawableTest {
+
+    private UserIconDrawable mDrawable;
+
+    @Test
+    public void getConstantState_shouldNotBeNull() {
+        final Bitmap b = BitmapFactory.decodeResource(
+                RuntimeEnvironment.application.getResources(),
+                R.drawable.home);
+        mDrawable = new UserIconDrawable(100 /* size */).setIcon(b).bake();
+
+        assertThat(mDrawable.getConstantState()).isNotNull();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index b209f4e..40353e7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -56,12 +56,11 @@
         allKeys.add(CategoryKey.CATEGORY_SECURITY);
         allKeys.add(CategoryKey.CATEGORY_ACCOUNT);
         allKeys.add(CategoryKey.CATEGORY_SYSTEM);
-        allKeys.add(CategoryKey.CATEGORY_SYSTEM_INPUT);
         allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
         allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
         // DO NOT REMOVE ANYTHING ABOVE
 
-        assertThat(allKeys.size()).isEqualTo(14);
+        assertThat(allKeys.size()).isEqualTo(13);
     }
 
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 021a96c..1683901 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -40,6 +40,7 @@
 
 import com.android.settingslib.SuggestionParser;
 import com.android.settingslib.TestConfig;
+import com.android.settingslib.drawer.TileUtilsTest;
 import static org.mockito.Mockito.atLeastOnce;
 
 import org.junit.Before;
@@ -179,7 +180,7 @@
 
         assertThat(outTiles.size()).isEqualTo(1);
         SuggestionParser parser = new SuggestionParser(mContext, null);
-        parser.filterSuggestions(outTiles, 0);
+        parser.filterSuggestions(outTiles, 0, false);
         assertThat(outTiles.size()).isEqualTo(0);
     }
 
@@ -303,16 +304,16 @@
         assertThat(outTiles.get(0).summary).isEqualTo("dynamic-summary");
     }
 
-    private ResolveInfo newInfo(boolean systemApp, String category) {
+    public static ResolveInfo newInfo(boolean systemApp, String category) {
         return newInfo(systemApp, category, null);
     }
 
-    private ResolveInfo newInfo(boolean systemApp, String category, String keyHint) {
+    private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint) {
         return newInfo(systemApp, category, keyHint, null, null);
     }
 
-    private ResolveInfo newInfo(boolean systemApp, String category, String keyHint, String iconUri,
-            String summaryUri) {
+    private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint,
+        String iconUri, String summaryUri) {
         ResolveInfo info = new ResolveInfo();
         info.system = systemApp;
         info.activityInfo = new ActivityInfo();
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7206127..499b6ae 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -38,7 +38,7 @@
 
     <bool name="def_bluetooth_on">true</bool>
     <bool name="def_wifi_display_on">false</bool>
-    <bool name="def_install_non_market_apps">false</bool>
+    <bool name="def_install_non_market_apps">true</bool>
     <bool name="def_package_verifier_enable">true</bool>
     <!-- Comma-separated list of location providers.
          Network location is off by default because it requires
@@ -227,4 +227,7 @@
 
     <!--  default setting for Settings.System.END_BUTTON_BEHAVIOR : END_BUTTON_BEHAVIOR_SLEEP -->
     <integer name="def_end_button_behavior">0x2</integer>
+
+    <!--Default settings for network recommendations. -->
+    <string name="def_network_recommendations_package" translatable="false">com.android.networkrecommendation</string>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 8bbc8c9..0676efd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -495,6 +495,9 @@
                 Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
                 GlobalSettingsProto.NETWORK_RECOMMENDATIONS_ENABLED);
         dumpSetting(s, p,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE,
+                GlobalSettingsProto.NETWORK_RECOMMENDATIONS_PACKAGE);
+        dumpSetting(s, p,
                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
                 GlobalSettingsProto.BLE_SCAN_ALWAYS_AVAILABLE);
         dumpSetting(s, p,
@@ -1399,9 +1402,6 @@
                 Settings.Secure.NIGHT_DISPLAY_CUSTOM_END_TIME,
                 SecureSettingsProto.NIGHT_DISPLAY_CUSTOM_END_TIME);
         dumpSetting(s, p,
-                Settings.Secure.BRIGHTNESS_USE_TWILIGHT,
-                SecureSettingsProto.BRIGHTNESS_USE_TWILIGHT);
-        dumpSetting(s, p,
                 Settings.Secure.ENABLED_VR_LISTENERS,
                 SecureSettingsProto.ENABLED_VR_LISTENERS);
         dumpSetting(s, p,
@@ -1429,18 +1429,6 @@
                 Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
                 SecureSettingsProto.SYSTEM_NAVIGATION_KEYS_ENABLED);
         dumpSetting(s, p,
-                Settings.Secure.DOWNLOADS_BACKUP_ENABLED,
-                SecureSettingsProto.DOWNLOADS_BACKUP_ENABLED);
-        dumpSetting(s, p,
-                Settings.Secure.DOWNLOADS_BACKUP_ALLOW_METERED,
-                SecureSettingsProto.DOWNLOADS_BACKUP_ALLOW_METERED);
-        dumpSetting(s, p,
-                Settings.Secure.DOWNLOADS_BACKUP_CHARGING_ONLY,
-                SecureSettingsProto.DOWNLOADS_BACKUP_CHARGING_ONLY);
-        dumpSetting(s, p,
-                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DOWNLOADS_DAYS_TO_RETAIN,
-                SecureSettingsProto.AUTOMATIC_STORAGE_MANAGER_DOWNLOADS_DAYS_TO_RETAIN);
-        dumpSetting(s, p,
                 Settings.Secure.QS_TILES,
                 SecureSettingsProto.QS_TILES);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8be9243..edcb9b5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2735,7 +2735,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 137;
+            private static final int SETTINGS_VERSION = 139;
 
             private final int mUserId;
 
@@ -3118,26 +3118,7 @@
                 }
 
                 if (currentVersion == 135) {
-                    // Version 135: Migrating the NETWORK_SCORER_APP setting to the
-                    // NETWORK_RECOMMENDATIONS_ENABLED setting.
-                    if (userId == UserHandle.USER_SYSTEM) {
-                        final SettingsState globalSettings = getGlobalSettingsLocked();
-                        Setting currentSetting = globalSettings.getSettingLocked(
-                            Global.NETWORK_SCORER_APP);
-                        if (!currentSetting.isNull()) {
-                            // A scorer was set so enable recommendations.
-                            globalSettings.insertSettingLocked(
-                                Global.NETWORK_RECOMMENDATIONS_ENABLED,
-                                "1", null, true,
-                                SettingsState.SYSTEM_PACKAGE_NAME);
-
-                            // and clear the scorer setting since it's no longer needed.
-                            globalSettings.insertSettingLocked(
-                                Global.NETWORK_SCORER_APP,
-                                null, null, true,
-                                SettingsState.SYSTEM_PACKAGE_NAME);
-                        }
-                    }
+                    // Version 135 no longer used.
                     currentVersion = 136;
                 }
 
@@ -3187,6 +3168,40 @@
 
                     currentVersion = 137;
                 }
+                if (currentVersion == 137) {
+                    // Version 138: Settings.Secure#INSTALL_NON_MARKET_APPS is deprecated and its
+                    // default value set to 1. The user can no longer change the value of this
+                    // setting through the UI.
+                    final SettingsState secureSetting = getSecureSettingsLocked(userId);
+                    if (!mUserManager.hasUserRestriction(
+                            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserHandle.of(userId))) {
+                        secureSetting.insertSettingLocked(Settings.Secure.INSTALL_NON_MARKET_APPS,
+                                "1", null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 138;
+                }
+
+                if (currentVersion == 138) {
+                    // Version 139: Applying the default to NETWORK_RECOMMENDATIONS_PACKAGE
+                    if (userId == UserHandle.USER_SYSTEM) {
+                        final SettingsState globalSettings = getGlobalSettingsLocked();
+                        final String defaultAppPackage = getContext().getResources()
+                                .getString(R.string.def_network_recommendations_package);
+
+                        // Set the network recommendations package name
+                        globalSettings.insertSettingLocked(
+                                Global.NETWORK_RECOMMENDATIONS_PACKAGE,
+                                defaultAppPackage, null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+
+                        // Clear the scorer setting since it's no longer needed.
+                        globalSettings.insertSettingLocked(
+                                Global.NETWORK_SCORER_APP,
+                                null, null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 139;
+                }
 
                 if (currentVersion != newVersion) {
                     Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
new file mode 100644
index 0000000..51e4373
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.providers.settings;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.SystemClock;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.List;
+
+@LargeTest
+public class InstallNonMarketAppsDeprecationTest extends BaseSettingsProviderTest {
+
+    private static final String TAG = InstallNonMarketAppsDeprecationTest.class.getSimpleName();
+    private static final long USER_RESTRICTION_CHANGE_TIMEOUT = 5000;
+
+    private UserManager mUm;
+    private boolean mHasUserRestriction;
+    private List<UserInfo> mCurrentUsers;
+
+    private String waitTillValueChanges(String errorMessage, String oldValue) {
+        boolean interrupted = false;
+        final long startTime = SystemClock.uptimeMillis();
+        String newValue = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+        while (newValue.equals(oldValue) && SystemClock.uptimeMillis() <= (startTime
+                + USER_RESTRICTION_CHANGE_TIMEOUT)) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException exc) {
+                interrupted = true;
+            }
+            newValue = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+        }
+        if (interrupted) {
+            Thread.currentThread().interrupt();
+        }
+        assertFalse(errorMessage, oldValue.equals(newValue));
+        return newValue;
+    }
+
+    private String getSecureSettingForUserViaShell(int userId) throws IOException {
+        StringBuilder sb = new StringBuilder("settings get --user ");
+        sb.append(userId + " secure ");
+        sb.append(Settings.Secure.INSTALL_NON_MARKET_APPS);
+        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(
+                InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                        sb.toString()).getFileDescriptor())));
+        String line = reader.readLine();
+        return line.trim();
+    }
+
+    @Before
+    public void setUp() {
+        mUm = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+        mHasUserRestriction = mUm.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+        mCurrentUsers = mUm.getUsers();
+    }
+
+    @Test
+    public void testValueDefaults() throws Exception {
+        if (mHasUserRestriction) {
+            // Default values don't apply when user restriction is set. Pass.
+            Log.w(TAG, "User restriction for unknown sources set. Skipping testValueDefaults test");
+            return;
+        }
+        String value = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+        assertEquals("install_non_market_apps should be 1", value, "1");
+
+        setSettingViaShell(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS, "0",
+                false);
+        resetSettingsViaShell(SETTING_TYPE_SECURE, Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+        value = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+        assertEquals("install_non_market_apps not reset to 1", value, "1");
+    }
+
+    @Test
+    public void testValueForNewUser() throws Exception {
+        UserInfo newUser = mUm.createUser("TEST_USER", 0);
+        String value = getSecureSettingForUserViaShell(newUser.id);
+        assertEquals("install_non_market_apps should be 1 for a new user", value, "1");
+    }
+
+    @Test
+    public void testValueRespectsUserRestriction() {
+        String value = getSetting(SETTING_TYPE_SECURE, Settings.Secure.INSTALL_NON_MARKET_APPS);
+        assertEquals(value, mHasUserRestriction ? "0" : "1");
+
+        mUm.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, !mHasUserRestriction);
+        value = waitTillValueChanges(
+                "Changing user restriction did not change the value of install_non_market_apps",
+                value);
+        assertTrue("Invalid value", value.equals("1") || value.equals("0"));
+
+        mUm.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, mHasUserRestriction);
+        value = waitTillValueChanges(
+                "Changing user restriction did not change the value of install_non_market_apps",
+                value);
+        assertTrue("Invalid value", value.equals("1") || value.equals("0"));
+    }
+
+    @After
+    public void tearDown() {
+        if (mUm.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
+                != mHasUserRestriction) {
+            mUm.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+                    mHasUserRestriction);
+        }
+        mUm.getUsers().forEach(user -> {
+            if (!mCurrentUsers.contains(user)) {
+                mUm.removeUser(user.id);
+            }
+        });
+    }
+}
diff --git a/packages/SystemUI/plugin/Android.mk b/packages/SystemUI/plugin/Android.mk
index 86527db..05ee6b2 100644
--- a/packages/SystemUI/plugin/Android.mk
+++ b/packages/SystemUI/plugin/Android.mk
@@ -27,3 +27,13 @@
 LOCAL_JAR_EXCLUDE_FILES := none
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# Dummy to generate .toc files.
+LOCAL_PACKAGE_NAME := PluginDummyLib
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := SystemUIPluginLib
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
index a2f84dc..13fc76c 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
+++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
@@ -15,11 +15,14 @@
 package com.android.systemui.plugin.testoverlayplugin;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import android.view.ViewTreeObserver.InternalInsetsInfo;
+import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
 import com.android.systemui.plugins.OverlayPlugin;
 
 public class SampleOverlayPlugin implements OverlayPlugin {
@@ -28,6 +31,9 @@
 
     private View mStatusBarView;
     private View mNavBarView;
+    private boolean mInputSetup;
+    private boolean mCollapseDesired;
+    private float mStatusBarHeight;
 
     @Override
     public int getVersion() {
@@ -43,6 +49,10 @@
 
     @Override
     public void onDestroy() {
+        if (mInputSetup) {
+            mStatusBarView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
+                    onComputeInternalInsetsListener);
+        }
         Log.d(TAG, "onDestroy");
         if (mStatusBarView != null) {
             mStatusBarView.post(
@@ -57,6 +67,9 @@
     public void setup(View statusBar, View navBar) {
         Log.d(TAG, "Setup");
 
+        int id = mPluginContext.getResources().getIdentifier("status_bar_height", "dimen",
+                "android");
+        mStatusBarHeight = mPluginContext.getResources().getDimension(id);
         if (statusBar instanceof ViewGroup) {
             mStatusBarView = LayoutInflater.from(mPluginContext)
                     .inflate(R.layout.colored_overlay, (ViewGroup) statusBar, false);
@@ -68,4 +81,28 @@
             ((ViewGroup) navBar).addView(mNavBarView);
         }
     }
+
+    @Override
+    public void setCollapseDesired(boolean collapseDesired) {
+        mCollapseDesired = collapseDesired;
+    }
+
+    @Override
+    public boolean holdStatusBarOpen() {
+        if (!mInputSetup) {
+            mInputSetup = true;
+            mStatusBarView.getViewTreeObserver().addOnComputeInternalInsetsListener(
+                    onComputeInternalInsetsListener);
+        }
+        return true;
+    }
+
+    final OnComputeInternalInsetsListener onComputeInternalInsetsListener = inoutInfo -> {
+        inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+        if (mCollapseDesired) {
+            inoutInfo.touchableRegion.set(new Rect(0, 0, 50000, (int) mStatusBarHeight));
+        } else {
+            inoutInfo.touchableRegion.set(new Rect(0, 0, 50000, 50000));
+        }
+    };
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
index 91a2604..f5074f7 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
@@ -21,4 +21,14 @@
     int VERSION = 1;
 
     void setup(View statusBar, View navBar);
+
+    default boolean holdStatusBarOpen() {
+        return false;
+    }
+
+    /**
+     * Only called if the plugin has returned true to holdStatusBarOpen().
+     */
+    default void setCollapseDesired(boolean collapseDesired) {
+    }
 }
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 6d76798..8cc2ce2 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -38,5 +38,5 @@
 -keep class ** extends android.support.v14.preference.PreferenceFragment
 -keep class com.android.systemui.tuner.*
 -keep class com.android.systemui.plugins.** {
-    public protected **;
+    public protected *;
 }
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 0000000..0615668
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 0000000..839e5ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 0000000..1480c865
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 0000000..66e11fb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 0000000..d2fe0c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 0000000..5923269
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 0000000..d0196e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 0000000..d3a2b39
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button.png
new file mode 100644
index 0000000..726643c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button_dark.png
new file mode 100644
index 0000000..31078f6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_accessibility_button_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
index ea03a50..4987f9b 100644
--- a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
+++ b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
@@ -15,5 +15,5 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
   <solid android:color="#61FFFFFF" />
-  <corners android:radius="@dimen/recents_grid_task_view_rounded_corners_radius"/>
+  <corners android:radius="@dimen/recents_grid_task_view_focused_frame_rounded_corners_radius"/>
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index 5e85ba0..6bd79a4 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -39,4 +39,13 @@
         android:contentDescription="@string/accessibility_ime_switch_button"
         android:scaleType="centerInside"
         />
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/accessibility_button"
+        android:layout_width="@dimen/navigation_extra_key_width"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="2dp"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_accessibility_button"
+        android:scaleType="centerInside"
+    />
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 63af3e0..c6452c0 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -21,6 +21,8 @@
 <com.android.systemui.statusbar.phone.PhoneStatusBarView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/status_bar_height"
     android:id="@+id/status_bar"
     android:background="@drawable/system_bar_background"
     android:orientation="vertical"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 92a9da9..51eefb6 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -59,9 +59,10 @@
         sysui:ignoreRightInset="true"
         android:importantForAccessibility="no"/>
 
-    <include layout="@layout/status_bar"
+    <FrameLayout
+        android:id="@+id/status_bar_container"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/status_bar_height" />
+        android:layout_height="wrap_content" />
 
     <include layout="@layout/brightness_mirror" />
 
@@ -73,7 +74,7 @@
     <include layout="@layout/status_bar_expanded"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:visibility="gone" />
+        android:visibility="invisible" />
 
     <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_in_front"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index e491257..7e3a457 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Terug"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Tuis"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Kieslys"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Oorsig"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Deursoek"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Vou uit"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeer"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Maak toe"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Maak toe"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Foon raak warm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Sommige kenmerke is beperk terwyl foon afkoel"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Jou foon sal outomaties probeer om af te koel. Jy kan steeds jou foon gebruik, maar dit sal dalk stadiger wees.\n\nJou foon sal normaalweg werk nadat dit afgekoel het."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Aanporboodskap vir wagwoord"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Opletberigte"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skermkiekies"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sekuriteit"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Gebruikerstatus"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Algemene boodskappe"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Berging"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d1aefcf..a793996 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"ተመለስ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"መነሻ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"ምናሌ"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"አጠቃላይ ዕይታ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ፈልግ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ካሜራ"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"ዘርጋ"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"አሳንስ"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"አሰናብት"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"ዝጋ"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ስልኩ እየሞቀ ነው"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ስልኩ እየቀዘቀዘ ሳለ አንዳንድ ባህሪዎች ይገደባሉ"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"የእርስዎ ስልክ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ስልክዎን መጠቀም ይችላሉ፣ ነገር ግን ሊንቀራፈፍ ይችላል።\n\nአንዴ ስልክዎ ከቀዘቀዘ በኋላ በመደበኝነት ያሄዳል።"</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"የይለፍ ቃል ጠይቅ"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ማንቂያዎች"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"ቅጽበታዊ ገጽ እይታዎች"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"ደህንነት"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"የተጠቃሚ ሁኔታ"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"አጠቃላይ መልዕክቶች"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"ማከማቻ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 77da13c..ae26d83 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -87,6 +87,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"رجوع"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"الرئيسية"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"القائمة"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"النظرة عامة"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"بحث"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"الكاميرا"</string>
@@ -679,7 +681,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"توسيع"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"تصغير"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"تجاهل"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"إغلاق"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"تزداد درجة حرارة الهاتف"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"يتم تقييد عمل بعض الميزات إلى أن تنخفض درجة حرارة الهاتف"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"سيحاول الهاتف تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام هاتفك، ولكن قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الهاتف، سيستعيد سرعته المعتادة."</string>
@@ -690,7 +692,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"طلب إدخال كلمة المرور"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"التنبيهات"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"لقطات الشاشة"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"الأمان"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"حالة المستخدمين"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"رسائل عامة"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"سعة التخزين"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index c55e94c..6d5a321 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Geri"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Ana səhifə"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"İcmal"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Axtar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Genişləndirin"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Kiçildin"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Yığışdırın"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Bağlayın"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon qızmağa başlayır"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Telefon soyuyana kimi bəzi funksiyalar məhdudlaşdırılır"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonunuz avtomatik olaraq soyumağa başlayacaq. Telefon istifadəsinə davam edə bilərsiniz, lakin sürəti yavaşlaya bilər.\n\nTelefonunuz soyuduqdan sonra normal işləyəcək."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Parol üçün bildiriş"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Siqnallar"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skrinşotlar"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Təhlükəsizlik"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"İstifadəçi statusu"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Ümumi Mesajlar"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Yaddaş"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index cc5ab4c..4769d98 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -84,6 +84,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Nazad"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Početna"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Meni"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Pregled"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pretražite"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odbaci"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon se zagrejao"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Neke funkcije su ograničene dok se telefon ne ohladi"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon će automatski pokušati da se ohladi. I dalje ćete moći da koristite telefon, ali će sporije reagovati.\n\nKada se telefon ohladi, normalno će raditi."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Upit za lozinku"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Obaveštenja"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimci ekrana"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Bezbednost"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status korisnika"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Opšte poruke"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Memorijski prostor"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index d084152..09d305d 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"На Галоўную старонку"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Меню"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Агляд"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Пошук"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -677,7 +679,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Разгарнуць"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Згарнуць"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Адхіліць"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Закрыць"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Тэлефон награваецца"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Некаторыя функцыі абмежаваны, пакуль тэлефон астывае"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Ваш тэлефон аўтаматычна паспрабуе астыць. Вы можаце па-ранейшаму карыстацца сваім тэлефонам, але ён можа працаваць больш павольна.\n\nПасля таго як ваш тэлефон астыне, ён будзе працаваць у звычайным рэжыме."</string>
@@ -688,7 +690,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Запыт пароля"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Абвесткi"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Здымкі экрана"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Бяспека"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Статус карыстальніка"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Агульныя паведамленні"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Захоўванне"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 08a8142..6dea2cf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Начало"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Меню"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Общ преглед"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Търсене"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Разгъване"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Намаляване"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Отхвърляне"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Затваряне"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Телефонът загрява"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Някои функции са ограничени, докато телефонът се охлажда"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефонът ви автоматично ще направи опит за охлаждане. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Подкана за парола"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сигнали"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Екранни снимки"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Сигурност"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Състояние на потребителя"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Общи съобщения"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 90aa1f5..e95f5ce 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"ফিরুন"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"হোম"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"মেনু"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"এক নজরে"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"অনুসন্ধান করুন"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ক্যামেরা"</string>
@@ -156,7 +158,7 @@
     <string name="accessibility_cell_data_off" msgid="8000803571751407635">"সেলুলার ডেটা বন্ধ আছে"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ব্লুটুথ টিথারিং৷"</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"বিমান মোড৷"</string>
-    <string name="accessibility_no_sims" msgid="3957997018324995781">"কোনো SIM কার্ড নেই।"</string>
+    <string name="accessibility_no_sims" msgid="3957997018324995781">"কোনো সিম কার্ড নেই।"</string>
     <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"পরিষেবা প্রদানকারীর নেটওয়ার্ক পরিবর্তিত হচ্ছে।"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"ব্যাটারির বিশদ বিবরণ খুলুন"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ ব্যাটারি রয়েছে৷"</string>
@@ -526,24 +528,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"শব্দ করে ও স্ক্রীনে ভেসে ওঠে"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
     <string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"বিজ্ঞপ্তি মনে করিয়ে দেওয়ার বিকল্পগুলি"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"১৫ মিনিট"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"৩০ মিনিট"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"১ ঘণ্টা"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"মনে করানো হবে না"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"পূর্বাবস্থায় ফিরুন"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> পরে আবার মনে করানো হবে"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"ব্যাটারির ব্যবহার"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"চার্জ করার সময় ব্যাটারি সেভার উপলব্ধ নয়"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ব্যাটারি সেভার"</string>
@@ -605,24 +598,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"চালু আছে"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"বন্ধ আছে"</string>
     <string name="nav_bar" msgid="1993221402773877607">"নেভিগেশন দন্ড"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"লেআউট"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"বাঁ"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"ডান"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"বোতামের ধরণ"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(ডিফল্ট)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"ক্লিপবোর্ড"</item>
+    <item msgid="5742013440802239414">"কীকোড"</item>
+    <item msgid="8748101184830239843">"মেনু / কীবোর্ড স্যুইচার"</item>
+    <item msgid="8175437057325747277">"কোনো কিছুই নয়"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"ভাগ করা (ডিফল্ট)"</item>
+    <item msgid="6210279084134579668">"কেন্দ্রস্থ"</item>
+    <item msgid="89143234390889289">"বাঁ দিকে সারিবদ্ধ"</item>
+    <item msgid="7715533883382410603">"ডান দিকে সারিবদ্ধ"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"মেনু / কীবোর্ড স্যুইচার"</string>
     <string name="save" msgid="2311877285724540644">"সংরক্ষণ করুন"</string>
     <string name="reset" msgid="2448168080964209908">"পুনরায় সেট করুন"</string>
@@ -630,8 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"ক্লিপবোর্ড"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"কাস্টম নেভিগেশান বোতাম"</string>
     <string name="keycode" msgid="7335281375728356499">"কীকোড"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"আইকন"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"টাইলগুলি যোগ করার জন্য টেনে আনুন"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"সরানোর জন্য এখানে টেনে আনুন"</string>
     <string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা করুন"</string>
@@ -682,28 +673,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"প্রসারিত করুন"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ছোটো করুন"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"খারিজ করুন"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"বন্ধ করুন"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ফোনটি গরম হচ্ছে"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ফোনটি ঠান্ডা হওয়ার সময় কিছু বৈশিষ্ট্য সীমিত হতে পারে"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"আপনার ফোনটি নিজে থেকেই ঠান্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠান্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"বাঁ"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"ডান"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"কাস্টমাইজ করার শর্টকাট"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"শর্টকাট"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"পাসওয়ার্ড জানতে চান"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"সতর্কতাগুলি"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"স্ক্রীনশটস"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"সাধারণ বার্তাগুলি"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"সঞ্চয়স্থান"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index e44e4bb..186d6f3 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -84,6 +84,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Nazad"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Dugme za početnu stranicu"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Dugme Meni"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Pregled"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Traži"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -448,7 +450,7 @@
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je prikačen"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Nazad."</string>
-    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran ostaje prikzan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Jasno mi je"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -608,7 +610,7 @@
   <string-array name="nav_bar_buttons">
     <item msgid="1545641631806817203">"Međumemorija"</item>
     <item msgid="5742013440802239414">"Kôd tipke"</item>
-    <item msgid="8748101184830239843">"Meni / Prebacivač tastature"</item>
+    <item msgid="8748101184830239843">"Prebacivač Meni / Tastatura"</item>
     <item msgid="8175437057325747277">"Nema"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
@@ -675,7 +677,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="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odbaci"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon se pregrijava"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Neke funkcije su ograničene dok se telefon hladi"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Vaš telefon će se automatski pokušati ohladiti. I dalje možete koristi telefon, ali će možda raditi sporije.\n\nNakon što se ohladi, telefon će normalno raditi."</string>
@@ -686,7 +688,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Traži lozinku"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimci ekrana"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sigurnost"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status korisnika"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Općenite poruke"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index b5cf3e4..0311231 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Enrere"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Pàgina d\'inici"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menú"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Visió general"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Càmera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Desplega"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimitza"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignora"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Tanca"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"El telèfon s\'està escalfant"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Algunes funcions estaran limitades mentre el telèfon es refreda"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"El telèfon provarà de refredar-se automàticament. Podràs continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Sol·licita la contrasenya"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Captures de pantalla"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Seguretat"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Estat de l\'usuari"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Missatges generals"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Emmagatzematge"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index f9ec15e..75b2a9a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Zpět"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Domů"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Přehled"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hledat"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
@@ -677,7 +679,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbalit"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovat"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Zrušit"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Zavřít"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon se zahřívá"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Některé funkce jsou při chladnutí omezeny"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž telefon vychladne, bude fungovat normálně."</string>
@@ -688,7 +690,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Výzva k zadání hesla"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornění"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snímky obrazovek"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Zabezpečení"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status uživatele"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Všeobecné zprávy"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Úložiště"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 206478c..7c2f954 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Tilbage"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Startskærm"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Oversigt"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Søg"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Udvid"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimer"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Afvis"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Luk"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefonen er ved at blive varm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Nogle funktioner er begrænsede, mens telefonen køler ned"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Din telefon forsøger automatisk at køle ned. Du kan stadig bruge telefonen, men den kører muligvis langsommere.\n\nNår din telefon er kølet ned, fungerer den normalt igen."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Spørg om adgangskode"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sikkerhed"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Brugerstatus"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Generelle meddelelser"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Lagerplads"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a317fa0..8916dbb 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Zurück"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Startbildschirm"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menü"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Übersicht"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Suchen"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Maximieren"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimieren"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Schließen"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Schließen"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Smartphone wird warm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Einige Funktionen sind während der Abkühlphase des Smartphones eingeschränkt"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Dein Smartphone kühlt sich automatisch ab. Du kannst dein Smartphone weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Smartphone abgekühlt ist, funktioniert es wieder normal."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Zur Passworteingabe auffordern"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Warnmeldungen"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sicherheit"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Nutzerstatus"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Nachrichten"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Speicher"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 08c5822..baee007 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Πίσω"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Αρχική οθόνη"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Μενού"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Επισκόπηση"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Αναζήτηση"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Φωτογραφική μηχανή"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Ελαχιστοποίηση"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Παράβλεψη"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Κλείσιμο"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Αύξηση θερμοκρασίας τηλεφώνου"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Το τηλέφωνό σας θα προσπαθήσει να μειώσει αυτόματα τη θερμοκρασία. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του τηλεφώνου σας, θα λειτουργεί ξανά κανονικά."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Προτροπή για κωδικό πρόσβασης"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ειδοποιήσεις"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Στιγμιότυπα οθόνης"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Ασφάλεια"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Κατάσταση χρήστη"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Γενικά μηνύματα"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Αποθηκευτικός χώρος"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 822c2df..e66cb04 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Back"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Home"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Overview"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dismiss"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Close"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Phone is getting warm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Some features limited while phone cools down"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Prompt for password"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Security"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"User status"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 822c2df..e66cb04 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Back"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Home"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Overview"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dismiss"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Close"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Phone is getting warm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Some features limited while phone cools down"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Prompt for password"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Security"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"User status"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 822c2df..e66cb04 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Back"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Home"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Overview"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimise"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dismiss"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Close"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Phone is getting warm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Some features limited while phone cools down"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Prompt for password"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Security"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"User status"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"General Messages"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 37019b1..a1fa331 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Atrás"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Página principal"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menú"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Recientes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Descartar"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Cerrar"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"El teléfono se está calentando"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Se limitarán algunas funciones mientras se enfría el teléfono"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Tu teléfono intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar correctamente."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar contraseña"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Seguridad"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Estado del usuario"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mensajes generales"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 75cd169..50a1b1d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Atrás"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Inicio"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menú"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Aplicaciones recientes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
@@ -528,24 +530,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"Emitir sonido y mostrar en pantalla"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"Controles de las notificaciones"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Opciones para posponer las notificaciones"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutos"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutos"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 hora"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"No posponer"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"DESHACER"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"Volverá a mostrarse en <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
@@ -607,24 +600,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"Sí"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"No"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"Diseño"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"Izquierda"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"Derecha"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"Tipo de botón"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(predeterminada)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"Portapapeles"</item>
+    <item msgid="5742013440802239414">"Código de teclado"</item>
+    <item msgid="8748101184830239843">"Menú/Cambio de teclado"</item>
+    <item msgid="8175437057325747277">"Ninguno"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"Dividida (predeterminada)"</item>
+    <item msgid="6210279084134579668">"Centrada"</item>
+    <item msgid="89143234390889289">"Alineada a la izquierda"</item>
+    <item msgid="7715533883382410603">"Alineada a la derecha"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"Menú/Cambio de teclado"</string>
     <string name="save" msgid="2311877285724540644">"Guardar"</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
@@ -632,8 +624,7 @@
     <string name="clipboard" msgid="1313879395099896312">"Portapapeles"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"Botón de navegación personalizada"</string>
     <string name="keycode" msgid="7335281375728356499">"Código de teclado"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"Icono"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastra para añadir funciones"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra aquí para quitar una función"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
@@ -684,28 +675,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Mostrar"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Rechazar"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Cerrar"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"El teléfono se está calentando"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Se limitan algunas funciones mientras el teléfono se enfría"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"El teléfono intentará enfriarse. Puedes seguir utilizándolo, pero es posible que funcione con mayor lentitud.\n\nUna vez que se haya enfriado, funcionará con normalidad."</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"Izquierda"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"Derecha"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"Personalizar el acceso directo"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"Acceso directo"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar contraseña"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mensajes generales"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 03613bd..1c40495 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Tagasi"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Kodu"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menüü"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Ülevaade"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Otsing"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kaamera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Laiendamine"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeeri"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Loobu"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Sule"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon soojeneb"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Mõned funktsioonid on piiratud, kuni telefon jahtub"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Teie telefon proovib automaatselt maha jahtuda. Saate telefoni ikka kasutada, kuid see võib olla aeglasem.\n\nKui telefon on jahtunud, töötab see tavapäraselt."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Parooli viip"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Teatised"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekraanipildid"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Turvalisus"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Kasutaja olek"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Üldised sõnumid"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Salvestusruum"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 115c848..241c9aa 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Atzera"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Hasiera"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menua"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Ikuspegi orokorra"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Bilatu"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Zabaldu"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizatu"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Baztertu"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Itxi"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Berotzen ari da telefonoa"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonoa automatikoki saiatuko da hozten. Hoztu bitartean, telefonoa erabiltzen jarrai dezakezu, baina mantsoago funtziona lezake.\n\nTelefonoaren tenperatura jaitsi bezain laster, ohi bezala funtzionatzen jarraituko du."</string>
@@ -681,10 +683,9 @@
     <string name="lockscreen_right" msgid="6093496261656102989">"Eskuinaldea"</string>
     <string name="lockscreen_customize" msgid="1288691376862981950">"Pertsonalizatu lasterbidea"</string>
     <string name="lockscreen_shortcut" msgid="3734369277470360642">"Lasterbidea"</string>
-    <string name="lockscreen_unlock" msgid="4934466194763269051">"Eskatu pasahizta"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"Eskatu pasahitza"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Abisuak"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Pantaila-argazkiak"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Segurtasuna"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Erabiltzailearen egoera"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mezu orokorrak"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Memoria"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 78af4b8..08ad029 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"برگشت"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"صفحهٔ اصلی"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"منو"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"نمای کلی"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"جستجو"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"دوربین"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"بزرگ کردن"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"کوچک کردن"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"نپذیرفتن"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"بستن"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"تلفن درحال گرم شدن است"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"وقتی تلفن درحال خنک شدن است، بعضی از قابلیت‌ها محدود می‌شوند"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"تلفنتان به‌طور خودکار سعی می‌کند خنک شود. همچنان می‌توانید از تلفنتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی تلفن خنک شد، عملکرد عادی‌اش از سرگرفته می‌شود."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"درخواست وارد کردن گذرواژه"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"هشدارها"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"عکس‌های صفحه‌نمایش"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"امنیت"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"وضعیت کاربر"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"پیام‌های عمومی"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"فضای ذخیره‌سازی"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index bc840a8..36bf542 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Takaisin"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Aloituspainike"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Valikko"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Viimeisimmät"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Haku"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Laajenna"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Pienennä"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ohita"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Sulje"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Puhelin lämpenee"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana."</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Puhelimesi yrittää automaattisesti jäähdyttää itsensä. Voit silti käyttää puhelinta, mutta se voi toimia hitaammin.\n\nKun puhelin on jäähtynyt, se toimii normaalisti."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Kysy salasanaa"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ilmoitukset"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Kuvakaappaukset"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Tietosuoja"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Käyttäjätila"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Yleiset viestit"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Tallennustila"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f69a85b..3ffb1fa 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Précédent"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Domicile"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Aperçu"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Réduire"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorer"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Fermer"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Le téléphone commence à chauffer"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Les fonctionnalités sont limitées pendant que le téléphone refroidit"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Demander le mot de passe"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Saisies d\'écran"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sécurité"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"État de l\'utilisateur"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Messages généraux"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Stockage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4a2f23f..61c5a07 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Retour"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Accueil"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Aperçu"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Réduire"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorer"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Fermer"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Le téléphone chauffe"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Fonctionnalités limitées pendant le refroidissement du téléphone"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Demander le mot de passe"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Captures d\'écran"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sécurité"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"État de l\'utilisateur"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Nouveaux messages"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Espace de stockage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e65f3b0..14d00ef 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Volver"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Inicio"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menú"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Visión xeral"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Despregar"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorar"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Pechar"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"O teléfono está quentando"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"O uso dalgunhas funcións é limitado mentres o teléfono arrefría"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"O teléfono tentará arrefriar automaticamente. Podes utilizalo, pero é probable que funcione máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitude de contrasinal"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de pantalla"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Seguranza"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Estado do usuario"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mensaxes xerais"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b120c7d..979a2bb 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"પાછળ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"હોમ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"મેનુ"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"વિહંગાવલોકન"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"શોધો"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"કૅમેરો"</string>
@@ -526,24 +528,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"અવાજ કરો અને સ્ક્રીન પર બતાવો"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
     <string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"સૂચના નિયંત્રણો"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"સૂચના સ્નૂઝ કરવાના વિકલ્પો"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"15 મિનિટ"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"30 મિનિટ"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 કલાક"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"સ્નૂઝ કરશો નહીં"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"પૂર્વવત્ કરો"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> માટે સ્નૂઝ કરો"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"બૅટરી વપરાશ"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ચાર્જિંગ દરમિયાન બૅટરી બચતકર્તા ઉપલબ્ધ નથી"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"બૅટરી બચતકર્તા"</string>
@@ -605,24 +598,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"ચાલુ"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"બંધ"</string>
     <string name="nav_bar" msgid="1993221402773877607">"નેવિગેશન બાર"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"લેઆઉટ"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"ડાબે"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"જમણે"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"બટનનો પ્રકાર"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(ડિફૉલ્ટ)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"ક્લિપબોર્ડ"</item>
+    <item msgid="5742013440802239414">"કીકોડ"</item>
+    <item msgid="8748101184830239843">"મેનૂ / કીબોર્ડ સ્વિચર"</item>
+    <item msgid="8175437057325747277">"કોઈ નહીં"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"વિભાજીત (ડિફૉલ્ટ)"</item>
+    <item msgid="6210279084134579668">"કેન્દ્રિત"</item>
+    <item msgid="89143234390889289">"ડાબે-સંરેખિત"</item>
+    <item msgid="7715533883382410603">"જમણે-સંરેખિત"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"મેનૂ / કીબોર્ડ સ્વિચર"</string>
     <string name="save" msgid="2311877285724540644">"સાચવો"</string>
     <string name="reset" msgid="2448168080964209908">"ફરીથી સેટ કરો"</string>
@@ -630,8 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"ક્લિપબોર્ડ"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"કસ્ટમ નેવિગેશન બટન"</string>
     <string name="keycode" msgid="7335281375728356499">"કીકોડ"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"આઇકન"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ટાઇલ્સ ઉમેરવા માટે ખેંચો"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"દૂર કરવા માટે અહીં ખેંચો"</string>
     <string name="qs_edit" msgid="2232596095725105230">"સંપાદિત કરો"</string>
@@ -682,28 +673,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"વિસ્તૃત કરો"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"નાનું કરો"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"છોડી દો"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"બંધ કરો"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ફોન ગરમ થઈ રહ્યો છે"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ફોન ઠંડો થાય ત્યાં સુધી કેટલીક સુવિધાઓ મર્યાદિત હોય છે"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"તમારો ફોન આપમેળે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"ડાબે"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"જમણે"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"શૉર્ટકટ કસ્ટમાઇઝ કરો"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"શૉર્ટકટ"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"પાસવર્ડ માટેનો સંકેત આપો"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"ચેતવણીઓ"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"સ્ક્રીનશૉટ"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"સામાન્ય સંદેશા"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"સ્ટોરેજ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 7676691..29dadd2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"वापस जाएं"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"होम"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"मेनू"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"अवलोकन"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"खोजें"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"कैमरा"</string>
@@ -532,7 +534,7 @@
     <string name="snooze_option_15_min" msgid="1068727451405610715">"15 मिनट"</string>
     <string name="snooze_option_30_min" msgid="867081342535195788">"30 मिनट"</string>
     <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 घंटा"</string>
-    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"यद नहीं दिलाएं"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"याद नहीं दिलाएं"</string>
     <string name="snooze_undo" msgid="6074877317002985129">"पहले जैसा करें"</string>
     <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> के लिए याद दिलाया गया"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"बैटरी उपयोग"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पेज <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करें"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"छोटा करें"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"खारिज करें"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"बंद करें"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"फ़ोन गर्म हो रहा है"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"फ़ोन के ठंडा होने के दौरान कुछ सुविधाएं सीमित होती हैं"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"आपका फ़ोन अपने आप ठंडा होने की कोशिश करेगा. आप अभी भी अपने फ़ोन का उपयोग कर सकते हैं, लेकिन हो सकता है कि यह धीमी गति से चले.\n\nठंडा हो जाने पर आपका फ़ोन सामान्य रूप से चलेगा."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"पासवर्ड के लिए संकेत दें"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचनाएं"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"स्‍क्रीनशॉट"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"सुरक्षा"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"उपयोगकर्ता स्थिति"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"सामान्य संदेश"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"जगह"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 07c725b..b706706 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -84,6 +84,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Natrag"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Početna"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Izbornik"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Pregled"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pretraži"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
@@ -673,7 +675,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="pip_phone_expand" msgid="5889780005575693909">"Proširivanje"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiziraj"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odbaci"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon se zagrijava"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Neke su značajke ograničene dok se telefon hladi"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Upit za zaporku"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snimke zaslona"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sigurnost"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status korisnika"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Općenite poruke"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 029e76b..ef573cb 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Vissza"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Főoldal"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menü"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Áttekintés"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Keresés"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Kibontás"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Kis méret"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Elvetés"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Bezárás"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"A telefon melegszik"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Bizonyos funkciók korlátozottan működnek a telefon hűlése közben"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"A telefon automatikusan megpróbál lehűlni. Továbbra is tudja használni a telefont, de elképzelhető, hogy működése lelassul.\n\nAmint a telefon lehűl, újra a szokásos módon működik majd."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Jelszókérés"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Értesítések"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Képernyőképek"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Biztonság"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Felhasználói állapot"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Általános üzenetek"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Tárhely"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 761bee1..ddcbdfe 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Հետ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Տուն"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Ցանկ"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Համատեսք"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Որոնել"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Ֆոտոխցիկ"</string>
@@ -534,7 +536,7 @@
     <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ժամ"</string>
     <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Չհետաձգել"</string>
     <string name="snooze_undo" msgid="6074877317002985129">"ՀԵՏԱՐԿԵԼ"</string>
-    <string name="snoozed_for_time" msgid="2390718332980204462">"Հետաձգվել է հետևյալ ժամանակով՝ <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"Հետաձգվել է <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>ով"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"Մարտկոցի օգտագործում"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Մարտկոցի տնտեսումը լիցքավորման ժամանակ հասանելի չէ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Մարտկոցի տնտեսում"</string>
@@ -608,7 +610,7 @@
     <item msgid="8175437057325747277">"Չկան"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
-    <item msgid="4967898371682516967">"Բաժանվածծ (կանխադրված)"</item>
+    <item msgid="4967898371682516967">"Բաժանված (կանխադրված)"</item>
     <item msgid="6210279084134579668">"Կենտրոնում"</item>
     <item msgid="89143234390889289">"Հավասարեցված ձախ"</item>
     <item msgid="7715533883382410603">"Հավասարեցված աջ"</item>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Ընդարձակել"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Ծալել"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Փակել"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Փակել"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Հեռախոսը տաքանում է"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ: Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով:"</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Պահանջել գաղտնաբառ"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ծանուցումներ"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Էկրանի պատկերներ"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Անվտանգություն"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Օգտվողի կարգավիճակը"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Ընդհանուր հաղորդագրություններ"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Հիշողություն"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 24a7b538..bbd7c90 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Kembali"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Utama"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Ringkasan"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Telusuri"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Luaskan"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalkan"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Tutup"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Tutup"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Ponsel menjadi hangat"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Beberapa fitur dibatasi saat ponsel mendingin"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Ponsel akan otomatis mencoba mendingin. Anda tetap dapat menggunakan ponsel, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, ponsel akan berjalan seperti biasa."</string>
@@ -680,9 +682,8 @@
     <string name="lockscreen_customize" msgid="1288691376862981950">"Sesuaikan pintasan"</string>
     <string name="lockscreen_shortcut" msgid="3734369277470360642">"Pintasan"</string>
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Minta sandi"</string>
-    <string name="notification_channel_alerts" msgid="4496839309318519037">"Lansiran"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikasi"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshot"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Keamanan"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status pengguna"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Pesan Umum"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Penyimpanan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 5f46b92..d04af35 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Til baka"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Heim"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Valmynd"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Yfirlit"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Leita"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Myndavél"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Stækka"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minnka"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Hunsa"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Loka"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Síminn er að hitna"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Sumir eiginleikar eru takmarkaðir þegar síminn kælir sig"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Síminn reynir sjálfkrafa að kæla sig. Þú getur enn notað símann en hann gæti verið hægvirkari.\n\nEftir að síminn hefur kælt sig niður virkar hann eðlilega."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Beiðni um aðgangsorð"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Tilkynningar"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skjámyndir"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Öryggi"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Staða notanda"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Almenn skilaboð"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Geymslurými"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 2441b7f..7b1e117 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Indietro"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Home"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Panoramica"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotocamera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Espandi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Riduci a icona"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignora"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Chiudi"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Il telefono si sta scaldando"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Alcune funzioni limitate durante il raffreddamento del telefono"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Il telefono cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il telefono funzionerà normalmente."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Richiedi password"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Avvisi"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshot"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sicurezza"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Stato utente"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Messaggi generali"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Spazio di archiviazione"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 280b9aa..c237fc6 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"הקודם"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"בית"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"תפריט"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"סקירה"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"חפש"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"מצלמה"</string>
@@ -675,7 +677,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"הרחב"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"מזער"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"סגור"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"סגור"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"הטלפון מתחמם"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"קירור הטלפון ייעשה באופן אוטומטי. תוכל עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
@@ -686,7 +688,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"בקש סיסמה"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"התראות"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"צילומי מסך"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"אבטחה"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"סטטוס המשתמש"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"הודעות כלליות"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"אחסון"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 015545e..14d1c42 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"戻る"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"ホーム"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"メニュー"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"最近"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"検索"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"カメラ"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"閉じる"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"閉じる"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"スマートフォンの温度が上昇中"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"スマートフォンのクールダウン中は一部の機能が制限されます"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"スマートフォンは自動的にクールダウンを行います。その間もスマートフォンを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"パスワードの入力"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"スクリーンショット"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"セキュリティ"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"ユーザー ステータス"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"一般メッセージ"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"ストレージ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index c75d83d..38c52fc 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"უკან"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"საწყისი"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"მენიუ"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"მიმოხილვა"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ძიება"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"კამერა"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"გაშლა"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ჩაკეცვა"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"დახურვა"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"დახურვა"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ტელეფონი ცხელდება"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"თქვენი ტელეფონი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"პაროლის მოთხოვნა"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"გაფრთხილებები"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"ეკრანის ანაბეჭდები"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"უსაფრთხოება"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"მომხმარებლის სტატუსი"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"ზოგადი შეტყობინებები"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"მეხსიერება"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index d86fcf9..0a8f3e7 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Артқа"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Үй"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Mәзір"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Шолу"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Іздеу"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Жаю"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Кішірейту"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Қабылдамау"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Жабу"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Телефон қызуда"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Телефон толық суығанға дейін, кейбір функциялардың жұмысы шектеледі"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефон автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nТелефон суығаннан кейін, оның жұмысы қалпына келеді."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Құпия сөзді сұрау"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Дабылдар"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоттар"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Қауіпсіздік"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Пайдаланушы күйі"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Жалпы хабарлар"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Жад"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index cfbba6e..0621623 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"ថយក្រោយ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"គេហ​ទំព័រ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"ម៉ឺនុយ"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"ទិដ្ឋភាព"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ស្វែងរក"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ម៉ាស៊ីន​ថត"</string>
@@ -602,16 +604,16 @@
     <string name="nav_bar_button_type" msgid="6947806619897153791">"ប្រភេទ​ប៊ូតុង"</string>
     <string name="nav_bar_default" msgid="8587114043070993007">"(លំនាំដើម)"</string>
   <string-array name="nav_bar_buttons">
-    <item msgid="1545641631806817203">"ក្ដារ​តម្បៀត​ខ្ទាស់"</item>
+    <item msgid="1545641631806817203">"អង្គចងចាំ"</item>
     <item msgid="5742013440802239414">"លេខកូដ​គ្រាប់ចុច"</item>
-    <item msgid="8748101184830239843">"កម្មវិធី​ប្តូរក្តារ​ចុច / ម៉ឺនុយ"</item>
+    <item msgid="8748101184830239843">"ម៉ឺនុយ / កម្មវិធី​ប្តូរក្តារ​ចុច"</item>
     <item msgid="8175437057325747277">"គ្មាន"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
     <item msgid="4967898371682516967">"បំបែក (លំនាំដើម)"</item>
     <item msgid="6210279084134579668">"ដាក់​នៅ​កណ្តាល"</item>
-    <item msgid="89143234390889289">"តម្រឹម​ខាងឆ្វេង"</item>
-    <item msgid="7715533883382410603">"តម្រឹម​ខាងស្ដាំ"</item>
+    <item msgid="89143234390889289">"តម្រឹម​ឆ្វេង"</item>
+    <item msgid="7715533883382410603">"តម្រឹមស្ដាំ"</item>
   </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"កម្មវិធីប្តូរក្តារចុច / ម៉ឺនុយ"</string>
     <string name="save" msgid="2311877285724540644">"រក្សាទុក"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"ពង្រីក"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"បង្រួម"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"បដិសេធ"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"បិទ"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ទូរសព្ទ​នេះ​កំពុង​កើន​កម្តៅ"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"មុខងារ​មួយ​ចំនួន​នឹង​មិន​អាច​ប្រើ​បាន​ពេញលេញ​នោះ​ទេ ខណៈពេល​ដែល​ទូរសព្ទ​កំពុង​បញ្ចុះ​កម្តៅ"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"ទូរសព្ទ​របស់អ្នក​នឹង​ព្យាយាម​បញ្ចុះ​កម្តៅ​ដោយ​ស្វ័យប្រវត្តិ។ អ្នក​នៅតែ​អាច​ប្រើ​ទូរសព្ទ​របស់អ្នក​បាន​ដដែល​ ប៉ុន្តែ​វា​នឹង​ដំណើរ​ការ​យឺត​ជាង​មុន។\n\nបន្ទាប់​ពី​ទូរសព្ទ​របស់អ្នក​ត្រជាក់​ជាង​មុន​ហើយ វា​នឹង​ដំណើរការ​ដូច​ធម្មតា។"</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"ជំរុញ​ឲ្យ​បញ្ចូល​ពាក្យ​សម្ងាត់"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ការ​ជូនដំណឹង"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"រូបថត​អេក្រង់"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"សុវត្ថិភាព"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"ស្ថានភាព​អ្នកប្រើ"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"សារ​ទូទៅ"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"ទំហំផ្ទុក"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 70a8809..79c5695 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"ಹಿಂದೆ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"ಮುಖಪುಟ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"ಮೆನು"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"ಸಮಗ್ರ ನೋಟ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ಹುಡುಕಿ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ಕ್ಯಾಮರಾ"</string>
@@ -526,24 +528,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"ಪರದೆಯ ಮೇಲೆ ಧ್ವನಿಮಾಡಿ ಮತ್ತು ಪಾಪ್ ಮಾಡಿ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"ಅಧಿಸೂಚನೆ ಸ್ನೂಜ್ ಆಯ್ಕೆಗಳು"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"15 ನಿಮಿಷಗಳು"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"30 ನಿಮಿಷಗಳು"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ಗಂಟೆ"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"ಸ್ನೂಜ್‌ ಮಾಡಬೇಡಿ"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"ರದ್ದುಮಾಡಿ"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ಗೆ ಸ್ನೂಜ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"ಬ್ಯಾಟರಿ ಬಳಕೆ"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ಚಾರ್ಜಿಂಗ್ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಸೇವರ್‌‌ ಲಭ್ಯವಿರುವುದಿಲ್ಲ"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ಬ್ಯಾಟರಿ ಸೇವರ್‌‌"</string>
@@ -605,24 +598,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"ಆನ್"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"ಆಫ್"</string>
     <string name="nav_bar" msgid="1993221402773877607">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"ಲೇಔಟ್"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"ಎಡ"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"ಬಲ"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"ಬಟನ್ ವಿಧ"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(ಡಿಫಾಲ್ಟ್‌)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"</item>
+    <item msgid="5742013440802239414">"ಕೀಕೋಡ್"</item>
+    <item msgid="8748101184830239843">"ಮೆನು / ಕೀಬೋರ್ಡ್ ಬದಲಾಯಿಸುವಿಕೆ"</item>
+    <item msgid="8175437057325747277">"ಯಾವುದೂ ಅಲ್ಲ"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"ವಿಭಜಿಸಲಾಗಿದೆ (ಡಿಫಾಲ್ಟ್‌)"</item>
+    <item msgid="6210279084134579668">"ಕೇಂದ್ರೀಕೃತ"</item>
+    <item msgid="89143234390889289">"ಎಡಕ್ಕೆ ಹೊಂದಿಸಿರುವುದು"</item>
+    <item msgid="7715533883382410603">"ಬಲಕ್ಕೆ ಹೊಂದಿಸಿರುವುದು"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"ಮೆನು / ಕೀಬೋರ್ಡ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
     <string name="save" msgid="2311877285724540644">"ಉಳಿಸು"</string>
     <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
@@ -630,8 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"ಕಸ್ಟಮ್ ನ್ಯಾವಿಗೇಷನ್ ಬಟನ್"</string>
     <string name="keycode" msgid="7335281375728356499">"ಕೀಕೋಡ್"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"ಐಕಾನ್‌"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ಟೈಲ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ತೆಗೆದುಹಾಕಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ಎಡಿಟ್"</string>
@@ -682,28 +673,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ಕುಗ್ಗಿಸಿ"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"ವಜಾಗೊಳಿಸಿ"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"ಮುಚ್ಚಿ"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ಫೋನ್ ಬಿಸಿಯಾಗುತ್ತಿದೆ"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸುತ್ತದೆ"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"ನಿಮ್ಮ ಫೋನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ, ಆದರೆ ಇದು ನಿಧಾನವಾಗಿರಬಹುದು.\n\nಒಮ್ಮೆ ನಿಮ್ಮ ಫೋನ್ ತಣ್ಣಗಾದ ನಂತರ ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ."</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"ಎಡ"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"ಬಲ"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"ಶಾರ್ಟ್‌ಕಟ್ ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"ಶಾರ್ಟ್‌ಕಟ್"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"ಪಾಸ್‌ವರ್ಡ್‌ ಕೇಳಿ"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"ಎಚ್ಚರಿಕೆಗಳು"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳು"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"ಸಾಮಾನ್ಯ ಸಂದೇಶಗಳು"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"ಸಂಗ್ರಹಣೆ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4b59ad2..f7071f8 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"뒤로"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"홈"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"메뉴"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"최근 사용"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"검색"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"카메라"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"펼치기"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"최소화"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"닫기"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"닫기"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"휴대전화 온도가 높음"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다."</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"휴대전화 온도를 자동으로 낮추려고 시도합니다. 휴대전화를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n휴대전화 온도가 낮아지면 정상적으로 작동됩니다."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"비밀번호 요청"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"알림"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"스크린샷"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"보안"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"사용자 상태"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"일반 메시지"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"저장소"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 53b1098..aca37b6 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Артка"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Үйгө"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Меню"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Көз жүгүртүү"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Издөө"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -620,7 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"Алмашуу буфери"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"Ыңгайлаштырылган чабыттоо баскычы"</string>
     <string name="keycode" msgid="7335281375728356499">"Баскыч коду"</string>
-    <string name="icon" msgid="8732339849035837289">"Сөлөкөт"</string>
+    <string name="icon" msgid="8732339849035837289">"Сүрөтчө"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Керектүү нерселерди сүйрөп кошуңуз"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Түзөтүү"</string>
@@ -671,18 +673,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Жайып көрсөтүү"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Кичирейтүү"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Этибарга албоо"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Жабуу"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Телефонуңуз ысып баратат"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Телефон сууганча айрым элементтердин иши чектелген"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефонуңуз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТелефонуңуз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
     <string name="lockscreen_left" msgid="6806490081187499505">"Сол жакта"</string>
     <string name="lockscreen_right" msgid="6093496261656102989">"Оң жакта"</string>
-    <string name="lockscreen_customize" msgid="1288691376862981950">"Кыска жолду ыңгайлаштыруу"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"Кыска жолду тууралоо"</string>
     <string name="lockscreen_shortcut" msgid="3734369277470360642">"Кыска жол"</string>
-    <string name="lockscreen_unlock" msgid="4934466194763269051">"Сырсөз үчүн ишарат"</string>
-    <string name="notification_channel_alerts" msgid="4496839309318519037">"Айгай кабарлар"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"Сырсөздү суроо"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"Эскертүүлөр"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоттор"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Коопсуздук"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Колдонуучунун абалы"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Жалпы билдирүүлөр"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Сактагыч"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index aea7812..4c7aafa 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"ກັບຄືນ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"ໜ້າທຳອິດ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"ເມນູ"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"​ພາບ​ຮວມ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ຊອກຫາ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ກ້ອງ"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"ຂະຫຍາຍ"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ຫຍໍ້"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"ປິດໄວ້"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"ປິດ"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ໂທລະສັບກຳລັງຮ້ອນຂຶ້ນ"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ຄຸນສົມບັດບາງຢ່າງຖືກຈຳກັດໄວ້ເນື່ອງໃນເວລາຫຼຸດອຸນຫະພູມຂອງໂທລະສັບ"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"ໂທລະສັບຂອງທ່ານຈະພະຍາຍາມລົດອຸນຫະພູມລົງ. ທ່ານຍັງຄົງສາມາດໃຊ້ໂທລະສັບຂອງທ່ານໄດ້ຢູ່, ແຕ່ມັນຈະເຮັດວຽກຊ້າລົງ.\n\nເມື່ອໂທລະສັບຂອງທ່ານບໍ່ຮ້ອນຫຼາຍແລ້ວ, ມັນຈະກັບມາເຮັດວຽກຕາມປົກກະຕິ."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"ຖາມຫາລະຫັດຜ່ານ"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ການເຕືອນ"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"ຮູບຖ່າຍໜ້າຈໍ"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"ຄວາມປອດໄພ"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"ສະຖານະຜູ້ໃຊ້"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"ຂໍ້ຄວາມທົ່ວໄປ"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"ບ່ອນເກັບຂໍ້ມູນ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 83f4d15..9438368 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Atgal"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Pagrindinis"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Meniu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Apžvalga"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Ieškoti"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparatas"</string>
@@ -675,7 +677,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Išskleisti"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Sumažinti"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Atsisakyti"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Uždaryti"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefonas kaista"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonas automatiškai bandys atvėsti. Telefoną vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai telefonas atvės, jis veiks įprastai."</string>
@@ -686,7 +688,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Paraginti įvesti slaptažodį"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Įspėjimai"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekrano kopijos"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sauga"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Naudotojų būsena"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Bendrieji pranešimai"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Saugykla"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 09581e8..29b227a 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -84,6 +84,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Atpakaļ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Sākums"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Izvēlne"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Pārskats"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Meklēt"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Izvērst"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizēt"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Noraidīt"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Aizvērt"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Tālrunis kļūst silts"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Dažas funkcijas ir ierobežotas, kamēr tālrunis mēģina atdzist"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Jūsu tālrunis automātiski mēģinās atdzist. Jūs joprojām varat izmantot tālruni, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz tālrunis būs atdzisis, tas darbosies normāli."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Pieprasīt paroli"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Brīdinājumi"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekrānuzņēmumi"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Drošība"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Lietotāju statuss"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Vispārīgi ziņojumi"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Krātuve"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 6db8e58..91bfd35 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Почетна страница"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Мени"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Краток преглед"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Пребарај"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Проширете"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Минимизирај"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Отфрли"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Затвори"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Телефонот се загрева"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Некои функции се ограничени додека телефонот се лади"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефонот автоматски ќе се обиде да се олади. Вие сепак ќе може да го користите, но тој може да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Побарај лозинка"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Предупредувања"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Слики од екранот"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Безбедност"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Кориснички статус"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Општи пораки"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Меморија"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 0cdd351..5fd5022 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"മടങ്ങുക"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"ഹോം"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"മെനു"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"കാഴ്ച"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"തിരയൽ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ക്യാമറ"</string>
@@ -526,24 +528,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"ശബ്ദമുണ്ടാക്കുക, സ്ക്രീനിൽ കാണിക്കുക"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
     <string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"അറിയിപ്പ് സ്‌നൂസ് ഓപ്ഷനുകൾ"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"15 മിനിറ്റ്"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"30 മിനിറ്റ്"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"ഒരു മണിക്കൂർ"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"സ്‌നൂസ് ‌ചെയ്യരുത്"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"പഴയപടിയാക്കുക"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> സമയത്തേക്ക് സ്‌നൂസ് ‌ചെയ്‌തു"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"ബാറ്ററി ഉപയോഗം"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ചാർജുചെയ്യുന്ന സമയത്ത് ബാറ്ററി സേവർ ലഭ്യമല്ല"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ബാറ്ററി സേവർ"</string>
@@ -605,24 +598,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"ഓൺ"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"ഓഫ്"</string>
     <string name="nav_bar" msgid="1993221402773877607">"നാവിഗേഷൻ ബാർ"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"ലേ‌ഔട്ട്"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"ഇടത്"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"വലത്"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"ബട്ടൺ തരം"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(ഡിഫോൾട്ട്)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"ക്ലിപ്പ്ബോർഡ്"</item>
+    <item msgid="5742013440802239414">"കീകോഡ്"</item>
+    <item msgid="8748101184830239843">"മെനു / കീബോർഡ് സ്വിച്ചർ"</item>
+    <item msgid="8175437057325747277">"ഒന്നുമില്ല"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"വിഭജിച്ചത് (ഡിഫോൾട്ട്)"</item>
+    <item msgid="6210279084134579668">"മധ്യഭാഗത്ത് വിന്യസിച്ചത്"</item>
+    <item msgid="89143234390889289">"ഇടതുവശത്ത് വിന്യസിച്ചത്"</item>
+    <item msgid="7715533883382410603">"വലതുവശത്ത് വിന്യസിച്ചത്"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"മെനു / കീബോർഡ് സ്വിച്ചർ"</string>
     <string name="save" msgid="2311877285724540644">"സംരക്ഷിക്കുക"</string>
     <string name="reset" msgid="2448168080964209908">"പുനഃസജ്ജമാക്കുക"</string>
@@ -630,8 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"ക്ലിപ്പ്ബോർഡ്"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"ഇഷ്ടാനുസൃത നാവിഗേഷൻ ബട്ടൺ"</string>
     <string name="keycode" msgid="7335281375728356499">"കീകോഡ്"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"ഐക്കൺ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ടൈലുകൾ ചേർക്കുന്നതിന് വലിച്ചിടുക"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"നീക്കംചെയ്യുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
     <string name="qs_edit" msgid="2232596095725105230">"എഡിറ്റുചെയ്യുക"</string>
@@ -682,28 +673,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"വികസിപ്പിക്കുക"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ചെറുതാക്കുക‍"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"നിരസിക്കുക"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"അടയ്‌ക്കുക"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ഫോൺ ചൂടായിക്കൊണ്ടിരിക്കുന്നു"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ഫോൺ തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തപ്പെടും"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"നിങ്ങളുടെ ഫോൺ സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഫോൺ ഉപയോഗിക്കാമെങ്കിലും പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കും.\n\nതണുത്തുകഴിഞ്ഞാൽ, ഫോൺ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കും."</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"ഇടത്"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"വലത്"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"കുറുക്കുവഴി ഇഷ്‌ടാനുസൃതമാക്കുക"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"കുറുക്കുവഴി"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"പാസ്‌വേഡ് ആവശ്യപ്പെടുക"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"അലേർട്ടുകൾ"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"സ്‌ക്രീൻഷോട്ടുകൾ"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"പൊതുവായ സന്ദേശങ്ങൾ"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"സ്റ്റോറേജ്"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index d184f84..1c0d8ea 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -81,6 +81,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Буцах"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Гэрийн"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Цэс"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Тойм"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Хайх"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камер"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Дэлгэх"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Багасгах"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Хаах"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Хаах"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Утас халж эхэлж байна"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Таны утас хөрж байх зуур зарим онцлогийг хязгаарласан"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Таны утас автоматаар хөрөх болно. Та утсаа ашиглаж болох хэдий ч удаан ажиллаж болзошгүй.\n\nТаны утас хөрсний дараагаар хэвийн ажиллана."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Нууц үг шаардах"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сануулга"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Дэлгэцийн зураг дарах"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Аюулгүй байдал"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Хэрэглэгчийн төлөв"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Энгийн зурвас"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Хадгалах сан"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index f26f1e5..47679c7 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"परत"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"मुख्‍यपृष्‍ठ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"मेनू"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"विहंगावलोकन"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"शोधा"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"कॅमेरा"</string>
@@ -526,24 +528,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"ध्वनी करा आणि स्क्रीनवर पॉप करा"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
     <string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"सूचना नियंत्रणे"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"सूचना स्नूझ पर्याय"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"15 मिनिटे"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"30 मिनिटे"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 तास"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"स्नूझ करू नका"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"पूर्ववत करा"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> साठी स्नूझ करा"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"बॅटरी वापर"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज करताना बॅटरी बचतकर्ता उपलब्ध नाही"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"बॅटरी बचतकर्ता"</string>
@@ -605,24 +598,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"चालू"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"बंद"</string>
     <string name="nav_bar" msgid="1993221402773877607">"नॅव्हिगेशन बार"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"लेआउट"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"डावा"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"उजवा"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"बटणाचा प्रकार"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(डीफॉल्ट)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"क्लिपबोर्ड"</item>
+    <item msgid="5742013440802239414">"कीकोड"</item>
+    <item msgid="8748101184830239843">"मेनू / कीबोर्ड स्विचर"</item>
+    <item msgid="8175437057325747277">"काहीही नाही"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"विभाजित (डीफॉल्ट)"</item>
+    <item msgid="6210279084134579668">"मध्यवर्ती"</item>
+    <item msgid="89143234390889289">"डावे-संरेखित"</item>
+    <item msgid="7715533883382410603">"उजवे-संरेखित"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"मेनू / कीबोर्ड स्विचर"</string>
     <string name="save" msgid="2311877285724540644">"जतन करा"</string>
     <string name="reset" msgid="2448168080964209908">"रीसेट करा"</string>
@@ -630,8 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"क्लिपबोर्ड"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"सानुकूल नेव्हिगेशन बटण"</string>
     <string name="keycode" msgid="7335281375728356499">"कीकोड"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"चिन्ह"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइल जोडण्यासाठी ड्रॅग करा"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"काढण्यासाठी येथे ड्रॅग करा"</string>
     <string name="qs_edit" msgid="2232596095725105230">"संपादित करा"</string>
@@ -682,28 +673,18 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करा"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"लहान करा"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"डिसमिस करा"</string>
+    <!-- no translation found for pip_phone_close (8416647892889710330) -->
+    <skip />
     <string name="high_temp_title" msgid="4589508026407318374">"फोन ऊष्ण होत आहे"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"फोन थंड होत असताना काही वैशिष्‍ट्ये मर्यादित असतात"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"आपला फोन स्वयंचलितपणे थंड होईल. आपण अद्यापही आपला फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nआपला फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"डावा"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"उजवा"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"शॉर्टकट सानुकूल करा"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"शॉर्टकट"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"संकेतशब्दासाठी संकेत"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचना"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"स्क्रीनशॉट"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"सर्वसाधारण संदेश"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"संचय"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 18fa6d0..7ed12dc17 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Kembali"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Rumah"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Ikhtisar"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cari"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Kembangkan"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimumkan"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ketepikan"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Tutup"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon semakin panas"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Sesetengah ciri adalah terhad semasa telefon menyejuk"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan telefon itu tetapi telefon tersebut mungkin berjalan lebih perlahan.\n\nSetelah telefon anda sejuk, telefon itu akan berjalan seperti biasa."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Gesa untuk kata laluan"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Makluman"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Tangkapan skrin"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Keselamatan"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status pengguna"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mesej Am"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 1c4a83e..c2b1e59 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"နောက်သို့"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"ပင်မစာမျက်နှာ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"မီနူး"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"ခြုံကြည့်မှု။"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ရှာဖွေရန်"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ကင်မရာ"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"ချဲ့ရန်"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ချုံ့ရန်"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"ပယ်ရန်"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"ပိတ်ရန်"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ဖုန်း ပူနွေးလာပါပြီ"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ဖုန်းကို အေးအောင်ပြုလုပ်နေစဉ်တွင် အချို့ဝန်ဆောင်မှုများကို ကန့်သတ်ထားပါသည်"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"သင့်ဖုန်းသည် အလိုအလျောက် ပြန်အေးသွားပါလိမ့်မည်။ ဖုန်းကို အသုံးပြုနိုင်ပါသေးသည် သို့သော် ပိုနှေးနိုင်ပါသည်။\n\nသင့်ဖုန်း အေးသွားသည်နှင့် ပုံမှန်အတိုင်း ပြန်အလုပ်လုပ်ပါလိမ့်မည်။"</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"စကားဝှက်ကို မေးရန်"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"သတိပေးချက်များ"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"မျက်နှာပြင်ဓာတ်ပုံများ"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"လုံခြုံရေး"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"အသုံးပြုသူ အခြေအနေ"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"အထွေထွေ မက်ဆေ့ဂျ်များ"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"သိုလှောင်မှုများ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index d546e92..60dcae8 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Tilbake"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Startside"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Meny"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Oversikt"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Søk"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -528,7 +530,7 @@
     <string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
     <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="notification_menu_gear_description" msgid="2204480013726775108">"varselinnstillinger"</string>
-    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"utsettelsesalternativer for varsler"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"slumrealternativer for varsler"</string>
     <string name="snooze_option_15_min" msgid="1068727451405610715">"15 minutter"</string>
     <string name="snooze_option_30_min" msgid="867081342535195788">"30 minutter"</string>
     <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 time"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Vis"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimer"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Avvis"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Lukk"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefonen begynner å bli varm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Enkelte funksjoner er begrenset mens telefonen kjøles ned"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonen din kommer til å prøve å kjøle seg ned automatisk. Du kan fremdeles bruke telefonen, men den kjører muligens saktere.\n\nTelefonen kommer til å kjøre som normalt, når den har kjølt seg ned."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Påminnelse for passord"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Varsler"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skjermdumper"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Sikkerhet"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Brukerstatus"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Generelle meldinger"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 4f65f63..ad450ba 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"पछाडि"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"गृह"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"मेनु"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"सारांश"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"खोज्नुहोस्"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"क्यामेरा"</string>
@@ -526,24 +528,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"आवाज निकाल्ने र स्क्रिनमा पपअप देखाउने"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
     <string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"सूचना सम्बन्धी नियन्त्रणहरू"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"सूचना स्नुज गर्ने विकल्पहरू"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"१५ मिनेट"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"३० मिनेट"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"१ घण्टा"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"स्नुज नगर्नुहोस्"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"अनडू गर्नुहोस्"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> का लागि स्नुज गरियो"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"ब्याट्री उपयोग"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज गर्ने समयमा ब्याट्री सेभर उपलब्ध छैन"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"ब्याट्री सेभर"</string>
@@ -605,24 +598,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"सक्रिय गर्नुहोस्"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"निष्क्रिय"</string>
     <string name="nav_bar" msgid="1993221402773877607">"नेभिगेशन पट्टी"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"लेआउट"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"बायाँ"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"दायाँ"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"बटनको प्रकार"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(पूर्वनिर्धारित)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"क्लिपबोर्ड"</item>
+    <item msgid="5742013440802239414">"किकोड"</item>
+    <item msgid="8748101184830239843">"मेनु / किबोर्ड परिवर्तक"</item>
+    <item msgid="8175437057325747277">"कुनै पनि होइन"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"विभाजित (पूर्वनिर्धारित)"</item>
+    <item msgid="6210279084134579668">"मध्य भागमा"</item>
+    <item msgid="89143234390889289">"बायाँतिर पङ्क्तिबद्ध"</item>
+    <item msgid="7715533883382410603">"दायाँतिर पङ्क्तिबद्ध"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"मेनु / किबोर्ड स्विचर"</string>
     <string name="save" msgid="2311877285724540644">"सुरक्षित गर्नुहोस्"</string>
     <string name="reset" msgid="2448168080964209908">"पुनःसेट गर्नु"</string>
@@ -630,8 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"क्लिपबोर्ड"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"अनुकूलनको नेभिगेशन बटन"</string>
     <string name="keycode" msgid="7335281375728356499">"Keycode"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"आइकन"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलहरू थप्न तान्नुहोस्"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"हटाउनका लागि यहाँ तान्नुहोस्"</string>
     <string name="qs_edit" msgid="2232596095725105230">"सम्पादन गर्नुहोस्"</string>
@@ -682,28 +673,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत गर्नुहोस्"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"सानो बनाउनुहोस्"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"खारेज गर्नुहोस्"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"बन्द गर्नुहोस्"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"फोन तातो भइरहेको छ"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"फोन चिसो हुँदै गर्दा केही विशेषताहरूलाई सीमित गरिन्छ"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"तपाईंको फोन स्वतः चिसो हुने प्रयास गर्नेछ। तपाईं अझै पनि आफ्नो फोनको प्रयोग गर्न सक्नुहुन्छ तर त्यो अझ ढिलो चल्न सक्छ।\n\nचिसो भएपछि तपाईंको फोन सामान्य गतिमा चल्नेछ।"</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"बायाँ"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"दायाँ"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"सर्टकट आफू अनुकूल पार्नुहोस्"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"सर्टकट"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"पासवर्ड माग्ने"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"अलर्टहरू"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"स्क्रिनशटहरू"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"सामान्य सन्देशहरू"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"भण्डारण"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index dbb7771..398f39d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Terug"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Homepage"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Overzicht"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Zoeken"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Sluiten"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Sluiten"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"De telefoon wordt warm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Je telefoon probeert automatisch af te koelen. Je kunt je telefoon nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de telefoon is afgekoeld, werkt deze weer normaal."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Wachtwoordprompt"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Meldingen"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Beveiliging"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Gebruikersstatus"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Algemene berichten"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Opslag"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 008f55aa..c06dfde 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"ਪਿੱਛੇ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"ਘਰ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"ਮੀਨੂ"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"ਰੂਪ-ਰੇਖਾ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ਖੋਜੋ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ਕੈਮਰਾ"</string>
@@ -533,7 +535,7 @@
     <string name="snooze_option_30_min" msgid="867081342535195788">"30 ਮਿੰਟ"</string>
     <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 ਘੰਟਾ"</string>
     <string name="snooze_option_dont_snooze" msgid="655446566007801922">"ਸਨੂਜ਼ ਨਾ ਕਰੋ"</string>
-    <string name="snooze_undo" msgid="6074877317002985129">"ਪਹਿਲਾਂ ਵਰਗਾ ਕਰੋ"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"ਅਣਕੀਤਾ ਕਰੋ"</string>
     <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ਲਈ ਸਨੂਜ਼ ਕੀਤਾ ਗਿਆ"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"ਬੈਟਰੀ ਵਰਤੋਂ"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
@@ -603,7 +605,7 @@
     <string name="nav_bar_default" msgid="8587114043070993007">"(ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</string>
   <string-array name="nav_bar_buttons">
     <item msgid="1545641631806817203">"ਕਲਿੱਪਬੋਰਡ"</item>
-    <item msgid="5742013440802239414">"ਕੀਕੋਡ"</item>
+    <item msgid="5742013440802239414">"ਕੀ-ਕੋਡ"</item>
     <item msgid="8748101184830239843">"ਮੀਨੂ/ਕੀ-ਬੋਰਡ ਸਵਿੱਚਰ"</item>
     <item msgid="8175437057325747277">"ਕੋਈ ਨਹੀਂ"</item>
   </string-array>
@@ -620,7 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"ਕਲਿੱਪਬੋਰਡ"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਆਵਾਗੌਣ ਬਟਨ"</string>
     <string name="keycode" msgid="7335281375728356499">"ਕੀਕੋਡ"</string>
-    <string name="icon" msgid="8732339849035837289">"ਚਿੰਨ੍ਹ"</string>
+    <string name="icon" msgid="8732339849035837289">"ਪ੍ਰਤੀਕ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ਟਾਇਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਘਸੀਟੋ"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -671,18 +673,17 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ਛੋਟਾ ਕਰੋ"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"ਖਾਰਜ ਕਰੋ"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"ਬੰਦ ਕਰੋ"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ਫ਼ੋਨ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ਫ਼ੋਨ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਿਤ ਹੁੰਦੀਆਂ ਹਨ"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਵੈਚਲਿਤ ਰੂਪ ਵਿੱਚ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰੰਤੂ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ ਵਧੇਰੇ ਹੌਲੀ ਚੱਲੇ।\n\nਇੱਕ ਵਾਰ ਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਧਾਰਨ ਤੌਰ \'ਤੇ ਚੱਲੇਗਾ।"</string>
     <string name="lockscreen_left" msgid="6806490081187499505">"ਖੱਬੇ"</string>
     <string name="lockscreen_right" msgid="6093496261656102989">"ਸੱਜੇ"</string>
-    <string name="lockscreen_customize" msgid="1288691376862981950">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਸ਼ਾਰਟਕੱਟ"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
     <string name="lockscreen_shortcut" msgid="3734369277470360642">"ਸ਼ਾਰਟਕੱਟ"</string>
-    <string name="lockscreen_unlock" msgid="4934466194763269051">"ਪਾਸਵਰਡ ਲਈ ਉਤਪ੍ਰੇਰਕ"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"ਪਾਸਵਰਡ ਲਈ ਪੁੱਛੋ"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ਸੁਚੇਤਨਾਵਾਂ"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"ਸੁਰੱਖਿਆ"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"ਵਰਤੋਂਕਾਰ ਸਥਿਤੀ"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"ਆਮ ਸੁਨੇਹੇ"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"ਸਟੋਰੇਜ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6e2d001..b93ef44 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Wróć"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Ekran główny"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Przegląd"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Szukaj"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Aparat"</string>
@@ -675,7 +677,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Rozwiń"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizuj"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Zamknij"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Zamknij"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon się nagrzewa"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale telefon może działać wolniej.\n\nGdy temperatura się obniży, telefon będzie działał normalnie."</string>
@@ -686,7 +688,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Pytaj o hasło"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerty"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Zrzuty ekranu"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Bezpieczeństwo"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Stan użytkownika"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Wiadomości"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Miejsce"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 4ab349c..9414a87 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Voltar"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Página inicial"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Visão geral"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Câmera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dispensar"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Fechar"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"O smartphone está esquentando"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Alguns recursos ficam limitados enquanto o smartphone é resfriado"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar senha"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de tela"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Segurança"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status do usuário"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index fa1f70e..f4ff723 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Anterior"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Página inicial"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Visão geral"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Câmara"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorar"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Fechar"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"O telemóvel está a aquecer"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"O telemóvel tenta arrefecer automaticamente. Pode continuar a utilizá-lo, mas este poderá funcionar mais lentamente.\n\nAssim que o telemóvel tiver arrefecido, funcionará normalmente."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar palavra-passe"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de ecrã"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Segurança"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Estado do utilizador"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 4ab349c..9414a87 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Voltar"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Página inicial"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Visão geral"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Câmera"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Dispensar"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Fechar"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"O smartphone está esquentando"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Alguns recursos ficam limitados enquanto o smartphone é resfriado"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitar senha"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturas de tela"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Segurança"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status do usuário"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mensagens gerais"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 7dc39d5..cf1304e 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -84,6 +84,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Înapoi"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Ecranul de pornire"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Meniu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Vizualizare generală"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Căutați"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cameră foto"</string>
@@ -675,7 +677,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Extindeți"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizați"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Respingeți"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Închideți"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefonul se încălzește"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Anumite funcții sunt limitate în timp ce telefonul se răcește"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonul va încerca automat să se răcească. Puteți folosi telefonul în continuare, dar este posibil să funcționeze mai lent.\n\nDupă ce se răcește, telefonul va funcționa normal."</string>
@@ -686,7 +688,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Solicitați parola"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerte"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Capturi de ecran"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Securitate"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Stare utilizator"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mesaje generale"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Stocare"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5806e23..e2a1f74 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Домой"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Меню"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Обзор."</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Поиск"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -677,7 +679,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Развернуть"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Свернуть"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Закрыть"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Закрыть"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Телефон нагревается"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Пока телефон не остынет, некоторые функции могут быть недоступны."</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Ваш телефон остынет автоматически.\n\nОбратите внимание, что до тех пор он может работать медленнее, чем обычно."</string>
@@ -688,7 +690,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Подсказка для пароля"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Уведомления"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Скриншоты"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Безопасность"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Статус пользователя"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Сообщения"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 8870fad..6ede3da 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"ආපසු"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"මුල් පිටුව"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"මෙනුව"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"දළ විශ්ලේෂණය"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"සොයන්න"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"කැමරාව"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"දිග හරින්න"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"කුඩා කරන්න"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"අස් කරන්න"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"වසන්න"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"දුරකථනය උණුසුම් වෙමින්"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"දුරකථනය සිසිල් වන අතරතුර සමහර විශේෂාංග සීමිත විය හැකිය"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"ඔබගේ දුරකථනය ස්වයංක්‍රියව සිසිල් වීමට උත්සාහ කරනු ඇත. ඔබට තවම ඔබේ දුරකථනය භාවිත කළ හැකිය, නමුත් එය සෙමින් ධාවනය විය හැකිය.\n\nඔබේ දුරකථනය සිසිල් වූ පසු, එය සාමාන්‍ය ලෙස ධාවනය වනු ඇත."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"මුරපදය සඳහා ප්‍රේරණය කරන්න"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ඇඟවීම්"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"තිර රු"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"ආරක්ෂාව"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"පරිශීලක තත්ත්වය"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"පොදු පණිවිඩ"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"ගබඩාව"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 8afa432..b81c191 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Späť"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Plocha"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Prehľad"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hľadať"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
@@ -677,7 +679,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbaliť"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovať"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Odmietnuť"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Zavrieť"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Teplota telefónu stúpa"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Váš telefón sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude telefón fungovať ako normálne."</string>
@@ -688,7 +690,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Požadovať heslo"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornenia"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Snímky obrazovky"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Zabezpečenie"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Stav používateľa"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Všeobecné správy"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Úložisko"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index f457847..e8ee37a 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Nazaj"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Začetni zaslon"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Meni"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Pregled"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Iskanje"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
@@ -677,7 +679,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Razširi"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiraj"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Opusti"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Zapri"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon se segreva"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Nekatere funkcije bodo med ohlajanjem omejene."</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se telefon ohladi, bo zopet deloval kot običajno."</string>
@@ -688,7 +690,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Poziv za geslo"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Opozorila"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Posnetki zaslona"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Varnost"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Stanje uporabnika"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Splošna sporočila"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Shramba"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index b7409a0..152ecef 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Prapa"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Faqja bazë"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menyja"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Përmbledhje"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Kërko"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Zgjero"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizo"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Hiqe"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Mbyll"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefoni po bëhet i ngrohtë"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Disa funksione janë të kufizuara kur telefoni është duke u ftohur"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefoni yt do të përpiqet automatikisht që të ftohet. Mund ta përdorësh përsëri telefonin, por ai mund të punojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të punojë si normalisht."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Kërko fjalëkalimin"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Sinjalizimet"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Pamjet e ekranit"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Siguria"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Statusi i përdoruesit"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mesazhe të përgjithshme"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Hapësira ruajtëse"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 4b0a577..4a80a94 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -84,6 +84,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Почетна"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Мени"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Преглед"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Претражите"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Прошири"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Умањи"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Одбаци"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Затвори"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Телефон се загрејао"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Неке функције су ограничене док се телефон не охлади"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Телефон ће аутоматски покушати да се охлади. И даље ћете моћи да користите телефон, али ће спорије реаговати.\n\nКада се телефон охлади, нормално ће радити."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Упит за лозинку"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Обавештења"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Снимци екрана"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Безбедност"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Статус корисника"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Опште поруке"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Меморијски простор"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c119da7..630225d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Tillbaka"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Startsida"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Meny"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Översikt"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Sök"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Utöka"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimera"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ignorera"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Stäng"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Mobilen börjar bli varm"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Vissa funktioner är begränsade medan mobilen svalnar"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Mobilen försöker svalna automatiskt. Du kan fortfarande använda mobilen, men den kan vara långsammare än vanligt.\n\nMobilen fungerar som vanligt när den har svalnat."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Kräv lösenord"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Varningar"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skärmdumpar"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Säkerhet"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Användarstatus"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Allmänna meddelanden"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 54fc443..4bf4d90 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Nyuma"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Nyumbani"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Muhtasari"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Tafuta"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -467,13 +469,13 @@
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Gonga ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Inaonyesha %s ya vidhibiti vya sauti. Telezesha kidole juu ili uondoe."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Imeficha vidhibiti vya sauti"</string>
-    <string name="system_ui_tuner" msgid="708224127392452018">"Kipokea Ishara cha SystemUI"</string>
+    <string name="system_ui_tuner" msgid="708224127392452018">"Kirekebishi cha kiolesura cha mfumo"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Onyesha asilimia ya betri iliyopachikwa"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Onyesha asilimia ya kiwango cha betri ndani ya aikoni ya sehemu ya arifa inapokuwa haichaji"</string>
     <string name="quick_settings" msgid="10042998191725428">"Mipangilio ya Haraka"</string>
     <string name="status_bar" msgid="4877645476959324760">"Sehemu ya kuonyesha hali"</string>
     <string name="overview" msgid="4018602013895926956">"Muhtasari"</string>
-    <string name="demo_mode" msgid="2532177350215638026">"Hali ya onyesho la UI ya mfumo"</string>
+    <string name="demo_mode" msgid="2532177350215638026">"Hali ya onyesho la kirekebishi cha kiolesura cha mfumo"</string>
     <string name="enable_demo_mode" msgid="4844205668718636518">"Washa hali ya onyesho"</string>
     <string name="show_demo_mode" msgid="2018336697782464029">"Onyesha hali ya onyesho"</string>
     <string name="status_bar_ethernet" msgid="5044290963549500128">"Ethaneti"</string>
@@ -490,12 +492,12 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Mtandao-hewa"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Wasifu wa kazini"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"Kinafurahisha kwa baadhi ya watu lakini si wote"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"Kipokea Ishara cha System UI kinakupa njia zaidi za kugeuza na kubadilisha kiolesura cha Android ili kikufae. Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika, au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"Kirekebishi cha kiolesura cha mfumo kinakupa njia zaidi za kugeuza na kubadilisha kiolesura cha Android ili kikufae. Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika, au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string>
     <string name="got_it" msgid="2239653834387972602">"Nimeelewa"</string>
-    <string name="tuner_toast" msgid="603429811084428439">"Hongera! Kipokea Ishara cha System UI kimeongezwa kwenye Mipangilio"</string>
+    <string name="tuner_toast" msgid="603429811084428439">"Hongera! Kirekebishi cha kiolesura cha mfumo kimeongezwa kwenye mipangilio"</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Ondoa kwenye Mipangilio"</string>
-    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Je, ungependa kuondoa Kipokea ishara cha SystemUI kwenye Mipangilio na uache kutumia vipengele vyake vyote?"</string>
+    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Je, ungependa kuondoa Kirekebishi cha kiolesura cha mfumo kwenye mipangilio na uache kutumia vipengele vyake vyote?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Programu haijasakinishwa kwenye kifaa chako"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Onyesha sekunde za saa"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Panua"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Punguza"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Ondoa"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Funga"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Joto la simu linaongezeka"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Baadhi ya vipengele havitatumika kwenye simu wakati inapoa"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Simu yako itajaribu kupoa kiotomatiki. Bado unaweza kutumia simu yako, lakini huenda ikafanya kazi polepole. \n\nPindi simu yako itakapopoa, itaendelea kufanya kazi kama kawaida."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Omba nenosiri"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Arifa"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Picha za skrini"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Usalama"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Hali ya mtumiaji"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Ujumbe wa Jumla"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Hifadhi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 68b99bf..5dea611 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"பின்செல்"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"முகப்பு"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"மெனு"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"மேலோட்டப் பார்வை"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"தேடு"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"கேமரா"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"விரி"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"சிறிதாக்கு"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"நிராகரி"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"மூடு"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"மொபைல் சூடாகிறது"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"மொபைலின் வெப்ப அளவு குறையும் போது, சில அம்சங்களைப் பயன்படுத்த முடியாது"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"உங்கள் மொபைலின் வெப்ப அளவு தானாகவே குறையும். தொடர்ந்து நீங்கள் மொபைலைப் பயன்படுத்தலாம், ஆனால் அதன் வேகம் குறைவாக இருக்கக்கூடும்.\n\nமொபைலின் வெப்ப அளவு குறைந்தவுடன், அது இயல்பு நிலையில் இயங்கும்."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"கடவுச்சொல்லைக் கேள்"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"விழிப்பூட்டல்கள்"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"ஸ்கிரீன் ஷாட்டுகள்"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"பாதுகாப்பு"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"பயனர் நிலை"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"பொதுச் செய்திகள்"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"சேமிப்பிடம்"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 69619bd0..eb5bc5e 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"వెనుకకు"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"హోమ్"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"మెను"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"అవలోకనం"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"శోధించు"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"కెమెరా"</string>
@@ -600,7 +602,7 @@
     <string name="nav_bar_left" msgid="731491280511316123">"ఎడమ"</string>
     <string name="nav_bar_right" msgid="2523774879720231974">"కుడి"</string>
     <string name="nav_bar_button_type" msgid="6947806619897153791">"బటన్ రకం"</string>
-    <string name="nav_bar_default" msgid="8587114043070993007">"(yadha prakaram)"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(డిఫాల్ట్)"</string>
   <string-array name="nav_bar_buttons">
     <item msgid="1545641631806817203">"క్లిప్‌బోర్డ్"</item>
     <item msgid="5742013440802239414">"కీకోడ్"</item>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"విస్తరింపజేయి"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"కనిష్టీకరించు"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"తీసివేయి"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"మూసివేయి"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"ఫోన్ వేడెక్కుతోంది"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"ఫోన్‌ను చల్లబరిచే క్రమంలో కొన్ని లక్షణాలు పరిమితం చేయబడ్డాయి"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"మీ ఫోన్ స్వయంచాలకంగా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"పాస్‌వర్డ్ కోసం ప్రాంప్ట్ చేయి"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"హెచ్చరికలు"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"స్క్రీన్‌షాట్‌లు"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"భద్రత"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"వినియోగదారు స్థితి"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"సాధారణ సందేశాలు"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"నిల్వ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ce7af3c..d64e2b9 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"กลับ"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"หน้าแรก"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"เมนู"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"ภาพรวม"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ค้นหา"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"กล้องถ่ายรูป"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"ขยาย"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"ย่อเล็กสุด"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"ปิด"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"ปิด"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"โทรศัพท์เริ่มเครื่องร้อน"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"คุณลักษณะบางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์ลดอุณหภูมิลง"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"โทรศัพท์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้โทรศัพท์ได้ แต่โทรศัพท์อาจทำงานช้าลง\n\nโทรศัพท์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"แจ้งให้ป้อนรหัสผ่าน"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"การแจ้งเตือน"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"ภาพหน้าจอ"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"ความปลอดภัย"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"สถานะของผู้ใช้"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"ข้อความทั่วไป"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"พื้นที่เก็บข้อมูล"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3e632c4..042f66d 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Bumalik"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Home"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Overview"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hanapin"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Palawakin"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"I-minimize"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"I-dismiss"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Isara"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Umiinit ang telepono"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Limitado ang ilang feature habang nagku-cool down ang telepono"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Awtomatikong susubukan ng iyong telepono na mag-cool down. Magagamit mo pa rin ang iyong telepono, ngunit maaaring mas mabagal ang paggana nito.\n\nKapag nakapag-cool down na ang iyong telepono, gagana na ito nang normal."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Mag-prompt para sa password"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Mga Alerto"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Mga Screenshot"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Seguridad"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Status ng user"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Mga Pangkalahatang Mensahe"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 3d00f1d..e46782a 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Geri"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Ana sayfa"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menü"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Genel Bakış"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Ara"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Genişlet"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Simge durumuna getir"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Kapat"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Kapat"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon ısınıyor"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefonunuz otomatik olarak soğumaya çalışacak. Bu sırada telefonunuzu kullanmaya devam edebilirsiniz ancak uygulamalar daha yavaş çalışabilir.\n\nTelefonunuz soğuduktan sonra normal şekilde çalışacaktır."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Şifre sor"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Uyarılar"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ekran görüntüleri"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Güvenlik"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Kullanıcı durumu"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Genel Mesajlar"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Depolama alanı"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4d928d9..591caa1 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -85,6 +85,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Головна"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Меню"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Огляд"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Пошук"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
@@ -677,7 +679,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Розгорнути"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Згорнути"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Вимкнути"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Закрити"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Телефон нагрівається"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Під час охолодження деякі функції обмежуються"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Ваш телефон охолоджуватиметься автоматично. Ви можете далі користуватися телефоном, але він може працювати повільніше.\n\nКоли телефон охолоне, він працюватиме належним чином."</string>
@@ -688,7 +690,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Запит пароля"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сповіщення"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Знімки екрана"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Безпека"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Статус користувача"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Загальні повідомлення"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Пам’ять"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index d8ab5f8..a4b0f87 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"واپس جائیں"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"ہوم"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"مینو"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"مجموعی جائزہ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"تلاش کریں"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"کیمرا"</string>
@@ -526,24 +528,15 @@
     <string name="notification_importance_high" msgid="3316555356062640222">"آواز نکالیں اور اسکرین پر پاپ کریں"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
     <string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
-    <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
-    <skip />
-    <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
-    <skip />
-    <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
-    <skip />
-    <!-- no translation found for snooze_option_15_min (1068727451405610715) -->
-    <skip />
-    <!-- no translation found for snooze_option_30_min (867081342535195788) -->
-    <skip />
-    <!-- no translation found for snooze_option_1_hour (1098086401880077154) -->
-    <skip />
-    <!-- no translation found for snooze_option_dont_snooze (655446566007801922) -->
-    <skip />
-    <!-- no translation found for snooze_undo (6074877317002985129) -->
-    <skip />
-    <!-- no translation found for snoozed_for_time (2390718332980204462) -->
-    <skip />
+    <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"اطلاع کے کنٹرولز"</string>
+    <string name="notification_menu_snooze_description" msgid="3653669438131034525">"اطلاع اسنوز کرنے کے اختیارات"</string>
+    <string name="snooze_option_15_min" msgid="1068727451405610715">"15 منٹ"</string>
+    <string name="snooze_option_30_min" msgid="867081342535195788">"30 منٹ"</string>
+    <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 گھنٹہ"</string>
+    <string name="snooze_option_dont_snooze" msgid="655446566007801922">"اسنوز نہ کريں"</string>
+    <string name="snooze_undo" msgid="6074877317002985129">"کالعدم کریں"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> کیلئے اسنوز کیا گیا"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"بیٹری کا استعمال"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"چارجنگ کے دوران بیٹری سیور دستیاب نہیں ہے"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"بیٹری سیور"</string>
@@ -605,24 +598,23 @@
     <string name="switch_bar_on" msgid="1142437840752794229">"آن"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"آف"</string>
     <string name="nav_bar" msgid="1993221402773877607">"نیویگیشن بار"</string>
-    <!-- no translation found for nav_bar_layout (3664072994198772020) -->
-    <skip />
-    <!-- no translation found for nav_bar_left (731491280511316123) -->
-    <skip />
-    <!-- no translation found for nav_bar_right (2523774879720231974) -->
-    <skip />
-    <!-- no translation found for nav_bar_button_type (6947806619897153791) -->
-    <skip />
-    <!-- no translation found for nav_bar_default (8587114043070993007) -->
-    <skip />
-    <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
-    <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
-    <!-- no translation found for nav_bar_buttons:2 (8748101184830239843) -->
-    <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
-    <!-- no translation found for nav_bar_layouts:0 (4967898371682516967) -->
-    <!-- no translation found for nav_bar_layouts:1 (6210279084134579668) -->
-    <!-- no translation found for nav_bar_layouts:2 (89143234390889289) -->
-    <!-- no translation found for nav_bar_layouts:3 (7715533883382410603) -->
+    <string name="nav_bar_layout" msgid="3664072994198772020">"لے آؤٹ"</string>
+    <string name="nav_bar_left" msgid="731491280511316123">"بائیں"</string>
+    <string name="nav_bar_right" msgid="2523774879720231974">"دائیں"</string>
+    <string name="nav_bar_button_type" msgid="6947806619897153791">"بٹن کی قسم"</string>
+    <string name="nav_bar_default" msgid="8587114043070993007">"(ڈیفالٹ)"</string>
+  <string-array name="nav_bar_buttons">
+    <item msgid="1545641631806817203">"کلپ بورڈ"</item>
+    <item msgid="5742013440802239414">"کی کوڈ"</item>
+    <item msgid="8748101184830239843">"مینو/ کی بورڈ سوئچر"</item>
+    <item msgid="8175437057325747277">"کوئی نہیں"</item>
+  </string-array>
+  <string-array name="nav_bar_layouts">
+    <item msgid="4967898371682516967">"تقسیم شدہ (ڈیفالٹ)"</item>
+    <item msgid="6210279084134579668">"بیچوں بیچ"</item>
+    <item msgid="89143234390889289">"بائیں جانب موافق کردہ"</item>
+    <item msgid="7715533883382410603">"دائیں جانب موافق کردہ"</item>
+  </string-array>
     <string name="menu_ime" msgid="4943221416525250684">"مینو/ کی بورڈ سوئچر"</string>
     <string name="save" msgid="2311877285724540644">"محفوظ کریں"</string>
     <string name="reset" msgid="2448168080964209908">"دوبارہ ترتیب دیں"</string>
@@ -630,8 +622,7 @@
     <string name="clipboard" msgid="1313879395099896312">"کلپ بورڈ"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"حسب ضرورت نیویگیشن بٹن"</string>
     <string name="keycode" msgid="7335281375728356499">"کی کوڈ"</string>
-    <!-- no translation found for icon (8732339849035837289) -->
-    <skip />
+    <string name="icon" msgid="8732339849035837289">"آئیکن"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ٹائٹلز شامل کرنے کیلئے گھسیٹیں"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ہٹانے کیلئے یہاں گھسیٹیں؟"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ترمیم کریں"</string>
@@ -682,28 +673,18 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"پھیلائیں"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"چھوٹی کریں"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"برخاست کریں"</string>
+    <!-- no translation found for pip_phone_close (8416647892889710330) -->
+    <skip />
     <string name="high_temp_title" msgid="4589508026407318374">"فون گرم ہو رہا ہے"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"فون کے ٹھنڈے ہو جانے تک کچھ خصوصیات محدود ہیں"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"آپ کا فون خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ ابھی بھی اپنا فون استعمال کر سکتے ہیں، مگر ہو سکتا ہے یہ سست چلے۔\n\nایک بار آپ کا فون ٹھنڈا ہوجائے تو یہ معمول کے مطابق چلے گا۔"</string>
-    <!-- no translation found for lockscreen_left (6806490081187499505) -->
-    <skip />
-    <!-- no translation found for lockscreen_right (6093496261656102989) -->
-    <skip />
-    <!-- no translation found for lockscreen_customize (1288691376862981950) -->
-    <skip />
-    <!-- no translation found for lockscreen_shortcut (3734369277470360642) -->
-    <skip />
-    <!-- no translation found for lockscreen_unlock (4934466194763269051) -->
-    <skip />
-    <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
-    <skip />
-    <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
-    <skip />
-    <!-- no translation found for notification_channel_security (7345516133431326347) -->
-    <skip />
-    <!-- no translation found for notification_channel_user_status (1436913581465146650) -->
-    <skip />
-    <!-- no translation found for notification_channel_storage (3077205683020695313) -->
-    <skip />
+    <string name="lockscreen_left" msgid="6806490081187499505">"بائیں"</string>
+    <string name="lockscreen_right" msgid="6093496261656102989">"دائیں"</string>
+    <string name="lockscreen_customize" msgid="1288691376862981950">"شارٹ کٹ کو حسب ضرورت بنائیں"</string>
+    <string name="lockscreen_shortcut" msgid="3734369277470360642">"شارٹ کٹ"</string>
+    <string name="lockscreen_unlock" msgid="4934466194763269051">"پاسورڈ کا اشارہ"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"الرٹس"</string>
+    <string name="notification_channel_screenshot" msgid="6314080179230000938">"اسکرین شاٹس"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"عمومی پیغامات"</string>
+    <string name="notification_channel_storage" msgid="3077205683020695313">"اسٹوریج"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index f72092b..a9c7b04 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Orqaga"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Uyga"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Umumiy nazar"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Qidirish"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
@@ -529,14 +531,14 @@
     <string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
     <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="notification_menu_gear_description" msgid="2204480013726775108">"bildirishnomalarni boshqarish elementlari"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"bildirishnoma sozlamalari"</string>
     <string name="notification_menu_snooze_description" msgid="3653669438131034525">"bildirishnomalarni kechiktirish parametrlari"</string>
     <string name="snooze_option_15_min" msgid="1068727451405610715">"15 daqiqa"</string>
     <string name="snooze_option_30_min" msgid="867081342535195788">"30 daqiqa"</string>
     <string name="snooze_option_1_hour" msgid="1098086401880077154">"1 soat"</string>
     <string name="snooze_option_dont_snooze" msgid="655446566007801922">"Kechiktirilmasin"</string>
     <string name="snooze_undo" msgid="6074877317002985129">"BEKOR QILISH"</string>
-    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> kechiktirildi"</string>
+    <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> muddatga kechiktirildi"</string>
     <string name="battery_panel_title" msgid="7944156115535366613">"Batareya sarfi"</string>
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Quvvat tejash rejimidan quvvatlash vaqtida foydalanib bo‘lmaydi"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Quvvat tejash rejimi"</string>
@@ -606,12 +608,12 @@
   <string-array name="nav_bar_buttons">
     <item msgid="1545641631806817203">"Vaqtinchalik xotira"</item>
     <item msgid="5742013440802239414">"Tugma kodi"</item>
-    <item msgid="8748101184830239843">"Menyu yoki klaviatura"</item>
-    <item msgid="8175437057325747277">"Hech qaysi"</item>
+    <item msgid="8748101184830239843">"Menyu/klaviaturani almashtirish"</item>
+    <item msgid="8175437057325747277">"Hech biri"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
-    <item msgid="4967898371682516967">"Bo‘lingan (standart)"</item>
-    <item msgid="6210279084134579668">"O‘rtaga tekislangan"</item>
+    <item msgid="4967898371682516967">"Alohida (standart)"</item>
+    <item msgid="6210279084134579668">"Markazda"</item>
     <item msgid="89143234390889289">"Chapga tekislangan"</item>
     <item msgid="7715533883382410603">"O‘ngga tekislangan"</item>
   </string-array>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Yoyish"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Yig‘ish"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Yopish"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Yopish"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Telefon qizib ketdi"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Telefon sovish paytida ayrim funksiyalar ishlamasligi mumkin"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Telefon avtomatik ravishda o‘zini sovitadi. Telefoningizdan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nTelefon sovishi bilan normal holatda ishlashni boshlaydi."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Parol uchun bildirgi"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ogohlantirishlar"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Skrinshotlar"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Xavfsizlik"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Foydalanuvchi holati"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Umumiy xabarlar"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Xotira"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e33328a..e2a87a4 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Quay lại"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Trang chủ"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Tổng quan"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Tìm kiếm"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Máy ảnh"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Mở rộng"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Thu nhỏ"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Loại bỏ"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Đóng"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Điện thoại đang nóng lên"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Điện thoại của bạn sẽ tự động nguội dần. Bạn vẫn có thể sử dụng điện thoại, nhưng điện thoại có thể chạy chậm hơn. \n\nSau khi đã nguội, điện thoại sẽ chạy bình thường."</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Lời nhắc nhập mật khẩu"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Cảnh báo"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Ảnh chụp màn hình"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Bảo mật"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Trạng thái người dùng"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Thông báo chung"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Bộ nhớ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index f754c38..bfaba9e 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"返回"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"主屏幕"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"菜单"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"概览"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜索"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相机"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"展开"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"关闭"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"关闭"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"手机温度上升中"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"手机降温时,部分功能的使用会受限制"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"您的手机将自动尝试降温。您依然可以使用您的手机,但是手机运行速度可能会更慢。\n\n手机降温后,就会恢复正常的运行速度。"</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"提示输入密码"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"提醒"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"屏幕截图"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"安全性"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"用户状态"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"常规消息"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"存储空间"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index ca882ab..4f299eb 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"返回"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"首頁"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"選單"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"概覽"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
@@ -673,7 +675,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"關閉"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"關閉"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"手機溫度正在上升"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"手機降溫時,部分功能會受限制"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"手機會自動嘗試降溫。您仍可以使用手機,但手機的運作速度可能較慢。\n\n手機降溫後便會恢復正常。"</string>
@@ -684,7 +686,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"輸入密碼提示"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"螢幕擷取畫面"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"安全性"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"使用者狀態"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"一般訊息"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 82ef5ee..1d28f14 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"返回"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"主螢幕"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"選單"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"總覽"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"關閉"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"關閉"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"手機變熱"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"手機降溫時,部分功能會受限"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"手機會自動嘗試降溫。你仍可繼續使用手機,但是手機的運作速度可能會較慢。\n\n手機降溫完畢後,就會恢復正常的運作速度。"</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"提示輸入密碼"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"快訊"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"螢幕擷取畫面"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"安全性"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"使用者狀態"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"一般訊息"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1a6b8d0..da0f2de 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -83,6 +83,8 @@
     <string name="accessibility_back" msgid="567011538994429120">"Emuva"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Ekhaya"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Imenyu"</string>
+    <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
+    <skip />
     <string name="accessibility_recent" msgid="5208608566793607626">"Buka konke"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Sesha"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Ikhamela"</string>
@@ -671,7 +673,7 @@
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Nweba"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Nciphisa"</string>
-    <string name="pip_phone_dismiss" msgid="1305916715402775904">"Cashisa"</string>
+    <string name="pip_phone_close" msgid="8416647892889710330">"Vala"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"Ifoni iyafudumala"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"Ezinye izici zikhawulelwe ngenkathi ifoni iphola"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"Ifoni yakho izozama ngokuzenzakalela ukuphola. Ungasasebenzisa ifoni yakho, kodwa ingasebenza ngokungasheshi.\n\nUma ifoni yakho isipholile, izosebenza ngokuvamile."</string>
@@ -682,7 +684,6 @@
     <string name="lockscreen_unlock" msgid="4934466194763269051">"Yalela iphasiwedi"</string>
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Izexwayiso"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Izithombe-skrini"</string>
-    <string name="notification_channel_security" msgid="7345516133431326347">"Ukuphepha"</string>
-    <string name="notification_channel_user_status" msgid="1436913581465146650">"Isimo somsebenzisi"</string>
+    <string name="notification_channel_general" msgid="4525309436693914482">"Imilayezo ejwayelekile"</string>
     <string name="notification_channel_storage" msgid="3077205683020695313">"Isitoreji"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
deleted file mode 100644
index bf0cba2..0000000
--- a/packages/SystemUI/res/values/arrays.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/colors.xml
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- BatteryMeterView parameters -->
-    <array name="batterymeter_color_levels">
-        <item>15</item>
-        <item>100</item>
-    </array>
-    <array name="batterymeter_color_values">
-        <item>@*android:color/battery_saver_mode_color</item>
-        <item>#FFFFFFFF</item>
-    </array>
-    <array name="batterymeter_bolt_points">
-        <item>73</item> <item>0</item>
-        <item>392</item><item>0</item>
-        <item>201</item><item>259</item>
-        <item>442</item><item>259</item>
-        <item>4</item>  <item>703</item>
-        <item>157</item><item>334</item>
-        <item>0</item>  <item>334</item>
-    </array>
-    <array name="batterymeter_plus_points">
-        <item>3</item><item>0</item>
-        <item>5</item><item>0</item>
-        <item>5</item><item>3</item>
-        <item>8</item><item>3</item>
-        <item>8</item><item>5</item>
-        <item>5</item><item>5</item>
-        <item>5</item><item>8</item>
-        <item>3</item><item>8</item>
-        <item>3</item><item>5</item>
-        <item>0</item><item>5</item>
-        <item>0</item><item>3</item>
-        <item>3</item><item>3</item>
-    </array>
-</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index ad5b108..1249f44 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -26,9 +26,6 @@
     <drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
     <color name="notification_list_shadow_top">#80000000</color>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
-    <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white -->
-    <color name="batterymeter_charge_color">#FFFFFFFF</color>
-    <color name="batterymeter_bolt_color">#FFFFFFFF</color>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
     <color name="system_warning_color">@*android:color/system_error</color>
     <color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b768f90..e69c4a3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -520,14 +520,6 @@
     <!-- How much two taps can be apart to still be recognized as a double tap on the lockscreen -->
     <dimen name="double_tap_slop">32dp</dimen>
 
-    <!-- Margin on the right side of the system icon group on Keyguard. -->
-    <fraction name="battery_button_height_fraction">10.5%</fraction>
-
-    <!-- Fraction value to smooth the edges of the battery icon. The path will be inset by this
-         fraction of a pixel.-->
-    <fraction name="battery_subpixel_smoothing_left">0%</fraction>
-    <fraction name="battery_subpixel_smoothing_right">0%</fraction>
-
     <dimen name="battery_margin_bottom">0dp</dimen>
 
     <!-- Padding at the end of the view that displays the mobile signal icons. If the view is
@@ -642,9 +634,6 @@
     <dimen name="docked_divider_handle_width">16dp</dimen>
     <dimen name="docked_divider_handle_height">2dp</dimen>
 
-    <dimen name="battery_height">14.5dp</dimen>
-    <dimen name="battery_width">9.5dp</dimen>
-
     <dimen name="battery_detail_graph_space_top">27dp</dimen>
     <dimen name="battery_detail_graph_space_bottom">27dp</dimen>
 
diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/res/values/dimens_grid.xml
index 5858443..febf65b8 100644
--- a/packages/SystemUI/res/values/dimens_grid.xml
+++ b/packages/SystemUI/res/values/dimens_grid.xml
@@ -22,6 +22,7 @@
   <dimen name="recents_grid_task_view_header_height">44dp</dimen>
   <dimen name="recents_grid_task_view_header_button_padding">8dp</dimen>
   <dimen name="recents_grid_task_view_focused_frame_thickness">8dp</dimen>
-  <dimen name="recents_grid_task_view_rounded_corners_radius">8dp</dimen>
+  <dimen name="recents_grid_task_view_rounded_corners_radius">4dp</dimen>
+  <dimen name="recents_grid_task_view_focused_frame_rounded_corners_radius">8dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 363b3e2..f7cf444 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -207,6 +207,8 @@
     <string name="accessibility_home">Home</string>
     <!-- Content description of the menu button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_menu">Menu</string>
+    <!-- Content description of the accessibility button in the navigation bar (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_accessibility_button">Accessibility</string>
     <!-- Content description of the recents button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_recent">Overview</string>
     <!-- Content description of the search button for accessibility. [CHAR LIMIT=NONE] -->
@@ -817,9 +819,6 @@
     <!-- Expanded Status Bar Header: Not charging [CHAR LIMIT=40] -->
     <string name="expanded_header_battery_not_charging">Not charging</string>
 
-    <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
-    <string name="battery_meter_very_low_overlay_symbol">!</string>
-
     <!-- Shows up when there is a user SSL CA Cert installed on the
          device.  Indicates to the user that SSL traffic can be intercepted.
          If the text fits on one line (~14 chars), it should start with a
@@ -1761,14 +1760,6 @@
         not appear on production builds ever. -->
     <string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string>
 
-    <!-- PIP allow minimize title. Non-translatable since it should
-        not appear on production builds ever. -->
-    <string name="pip_allow_minimize_title" translatable="false">Allow PIP to minimize</string>
-
-    <!-- PIP allow minimize description. Non-translatable since it should
-        not appear on production builds ever. -->
-    <string name="pip_allow_minimize_summary" translatable="false">Allow PIP to minimize slightly offscreen</string>
-
     <!-- Tuner string -->
     <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string>
     <!-- Tuner string -->
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 94a7c07..6198ab7 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -131,12 +131,6 @@
           android:summary="@string/pip_drag_to_dismiss_summary"
           sysui:defValue="false" />
 
-        <com.android.systemui.tuner.TunerSwitch
-            android:key="pip_allow_minimize"
-            android:title="@string/pip_allow_minimize_title"
-            android:summary="@string/pip_allow_minimize_summary"
-            sysui:defValue="true" />
-
     </PreferenceScreen>
 
     <PreferenceScreen
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
old mode 100755
new mode 100644
index 5a6afca..9068079
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -16,169 +16,40 @@
 
 package com.android.systemui;
 
-import android.animation.ArgbEvaluator;
-import android.annotation.Nullable;
 import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.database.ContentObserver;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
 import android.provider.Settings;
-
+import com.android.settingslib.graph.BatteryMeterDrawableBase;
 import com.android.systemui.statusbar.policy.BatteryController;
 
-public class BatteryMeterDrawable extends Drawable implements
+public class BatteryMeterDrawable extends BatteryMeterDrawableBase implements
         BatteryController.BatteryStateChangeCallback {
 
-    private static final float ASPECT_RATIO = 9.5f / 14.5f;
-    public static final String TAG = BatteryMeterDrawable.class.getSimpleName();
     public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
 
-    private static final boolean SINGLE_DIGIT_PERCENT = false;
-
-    private static final int FULL = 96;
-
-    private static final float BOLT_LEVEL_THRESHOLD = 0.3f;  // opaque bolt below this fraction
-
-    private final int[] mColors;
-    private final int mIntrinsicWidth;
-    private final int mIntrinsicHeight;
-
-    private boolean mShowPercent;
-    private float mButtonHeightFraction;
-    private float mSubpixelSmoothingLeft;
-    private float mSubpixelSmoothingRight;
-    private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
-            mPlusPaint;
-    private float mTextHeight, mWarningTextHeight;
-    private int mIconTint = Color.WHITE;
-    private float mOldDarkIntensity = 0f;
-
-    private int mHeight;
-    private int mWidth;
-    private String mWarningString;
-    private final int mCriticalLevel;
-    private int mChargeColor;
-    private final float[] mBoltPoints;
-    private final Path mBoltPath = new Path();
-    private final float[] mPlusPoints;
-    private final Path mPlusPath = new Path();
-
-    private final RectF mFrame = new RectF();
-    private final RectF mButtonFrame = new RectF();
-    private final RectF mBoltFrame = new RectF();
-    private final RectF mPlusFrame = new RectF();
-
-    private final Path mShapePath = new Path();
-    private final Path mClipPath = new Path();
-    private final Path mTextPath = new Path();
-
     private BatteryController mBatteryController;
-    private boolean mPowerSaveEnabled;
-
-    private int mDarkModeBackgroundColor;
-    private int mDarkModeFillColor;
-
-    private int mLightModeBackgroundColor;
-    private int mLightModeFillColor;
-
-    private final SettingObserver mSettingObserver;
-
-    private final Context mContext;
-
-    private int mLevel = -1;
-    private boolean mPluggedIn;
-    private boolean mListening;
+    private SettingObserver mSettingObserver;
 
     public BatteryMeterDrawable(Context context, int frameColor) {
-        mContext = context;
+        super(context, frameColor);
+
         mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));
-        final Resources res = context.getResources();
-        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
-        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
-
-        final int N = levels.length();
-        mColors = new int[2*N];
-        for (int i=0; i<N; i++) {
-            mColors[2*i] = levels.getInt(i, 0);
-            mColors[2*i+1] = colors.getColor(i, 0);
-        }
-        levels.recycle();
-        colors.recycle();
-        updateShowPercent();
-        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
-        mCriticalLevel = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
-        mButtonHeightFraction = context.getResources().getFraction(
-                R.fraction.battery_button_height_fraction, 1, 1);
-        mSubpixelSmoothingLeft = context.getResources().getFraction(
-                R.fraction.battery_subpixel_smoothing_left, 1, 1);
-        mSubpixelSmoothingRight = context.getResources().getFraction(
-                R.fraction.battery_subpixel_smoothing_right, 1, 1);
-
-        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mFramePaint.setColor(frameColor);
-        mFramePaint.setDither(true);
-        mFramePaint.setStrokeWidth(0);
-        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
-        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mBatteryPaint.setDither(true);
-        mBatteryPaint.setStrokeWidth(0);
-        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
-        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
-        mTextPaint.setTypeface(font);
-        mTextPaint.setTextAlign(Paint.Align.CENTER);
-
-        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mWarningTextPaint.setColor(mColors[1]);
-        font = Typeface.create("sans-serif", Typeface.BOLD);
-        mWarningTextPaint.setTypeface(font);
-        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
-
-        mChargeColor = context.getColor(R.color.batterymeter_charge_color);
-
-        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
-        mBoltPoints = loadBoltPoints(res);
-
-        mPlusPaint = new Paint(mBoltPaint);
-        mPlusPoints = loadPlusPoints(res);
-
-        mDarkModeBackgroundColor =
-                context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
-        mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
-        mLightModeBackgroundColor =
-                context.getColor(R.color.light_mode_icon_color_dual_tone_background);
-        mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
-
-        mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
-        mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
     }
 
     @Override
-    public int getIntrinsicHeight() {
-        return mIntrinsicHeight;
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        setBatteryLevel(level);
+        setPluggedIn(pluggedIn);
     }
 
     @Override
-    public int getIntrinsicWidth() {
-        return mIntrinsicWidth;
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        setPowerSave(isPowerSave);
     }
 
     public void startListening() {
-        mListening = true;
         mContext.getContentResolver().registerContentObserver(
                 Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
         updateShowPercent();
@@ -186,326 +57,18 @@
     }
 
     public void stopListening() {
-        mListening = false;
         mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
         mBatteryController.removeCallback(this);
     }
 
-    public void disableShowPercent() {
-        mShowPercent = false;
-        postInvalidate();
-    }
-
-    private void postInvalidate() {
-        scheduleSelf(this::invalidateSelf, 0);
+    protected void updateShowPercent() {
+        setShowPercent(0 != Settings.System.getInt(mContext.getContentResolver(),
+                SHOW_PERCENT_SETTING, 0));
     }
 
     public void setBatteryController(BatteryController batteryController) {
         mBatteryController = batteryController;
-        mPowerSaveEnabled = mBatteryController.isPowerSave();
-    }
-
-    @Override
-    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        mLevel = level;
-        mPluggedIn = pluggedIn;
-
-        postInvalidate();
-    }
-
-    @Override
-    public void onPowerSaveChanged(boolean isPowerSave) {
-        mPowerSaveEnabled = isPowerSave;
-        invalidateSelf();
-    }
-
-    private static float[] loadBoltPoints(Resources res) {
-        final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
-        int maxX = 0, maxY = 0;
-        for (int i = 0; i < pts.length; i += 2) {
-            maxX = Math.max(maxX, pts[i]);
-            maxY = Math.max(maxY, pts[i + 1]);
-        }
-        final float[] ptsF = new float[pts.length];
-        for (int i = 0; i < pts.length; i += 2) {
-            ptsF[i] = (float)pts[i] / maxX;
-            ptsF[i + 1] = (float)pts[i + 1] / maxY;
-        }
-        return ptsF;
-    }
-
-    private static float[] loadPlusPoints(Resources res) {
-        final int[] pts = res.getIntArray(R.array.batterymeter_plus_points);
-        int maxX = 0, maxY = 0;
-        for (int i = 0; i < pts.length; i += 2) {
-            maxX = Math.max(maxX, pts[i]);
-            maxY = Math.max(maxY, pts[i + 1]);
-        }
-        final float[] ptsF = new float[pts.length];
-        for (int i = 0; i < pts.length; i += 2) {
-            ptsF[i] = (float)pts[i] / maxX;
-            ptsF[i + 1] = (float)pts[i + 1] / maxY;
-        }
-        return ptsF;
-    }
-
-    @Override
-    public void setBounds(int left, int top, int right, int bottom) {
-        super.setBounds(left, top, right, bottom);
-        mHeight = bottom - top;
-        mWidth = right - left;
-        mWarningTextPaint.setTextSize(mHeight * 0.75f);
-        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
-    }
-
-    private void updateShowPercent() {
-        mShowPercent = 0 != Settings.System.getInt(mContext.getContentResolver(),
-                SHOW_PERCENT_SETTING, 0);
-    }
-
-    private int getColorForLevel(int percent) {
-
-        // If we are in power save mode, always use the normal color.
-        if (mPowerSaveEnabled) {
-            return mColors[mColors.length-1];
-        }
-        int thresh, color = 0;
-        for (int i=0; i<mColors.length; i+=2) {
-            thresh = mColors[i];
-            color = mColors[i+1];
-            if (percent <= thresh) {
-
-                // Respect tinting for "normal" level
-                if (i == mColors.length-2) {
-                    return mIconTint;
-                } else {
-                    return color;
-                }
-            }
-        }
-        return color;
-    }
-
-    public void setDarkIntensity(float darkIntensity) {
-        if (darkIntensity == mOldDarkIntensity) {
-            return;
-        }
-        int backgroundColor = getBackgroundColor(darkIntensity);
-        int fillColor = getFillColor(darkIntensity);
-        setColors(fillColor, backgroundColor);
-        mOldDarkIntensity = darkIntensity;
-    }
-
-    public void setColors(int fillColor, int backgroundColor) {
-        mIconTint = fillColor;
-        mFramePaint.setColor(backgroundColor);
-        mBoltPaint.setColor(fillColor);
-        mChargeColor = fillColor;
-        invalidateSelf();
-    }
-
-    private int getBackgroundColor(float darkIntensity) {
-        return getColorForDarkIntensity(
-                darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
-    }
-
-    private int getFillColor(float darkIntensity) {
-        return getColorForDarkIntensity(
-                darkIntensity, mLightModeFillColor, mDarkModeFillColor);
-    }
-
-    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
-        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
-    }
-
-    @Override
-    public void draw(Canvas c) {
-        final int level = mLevel;
-
-        if (level == -1) return;
-
-        float drawFrac = (float) level / 100f;
-        final int height = mHeight;
-        final int width = (int) (ASPECT_RATIO * mHeight);
-        int px = (mWidth - width) / 2;
-
-        final int buttonHeight = (int) (height * mButtonHeightFraction);
-
-        mFrame.set(0, 0, width, height);
-        mFrame.offset(px, 0);
-
-        // button-frame: area above the battery body
-        mButtonFrame.set(
-                mFrame.left + Math.round(width * 0.25f),
-                mFrame.top,
-                mFrame.right - Math.round(width * 0.25f),
-                mFrame.top + buttonHeight);
-
-        mButtonFrame.top += mSubpixelSmoothingLeft;
-        mButtonFrame.left += mSubpixelSmoothingLeft;
-        mButtonFrame.right -= mSubpixelSmoothingRight;
-
-        // frame: battery body area
-        mFrame.top += buttonHeight;
-        mFrame.left += mSubpixelSmoothingLeft;
-        mFrame.top += mSubpixelSmoothingLeft;
-        mFrame.right -= mSubpixelSmoothingRight;
-        mFrame.bottom -= mSubpixelSmoothingRight;
-
-        // set the battery charging color
-        mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
-
-        if (level >= FULL) {
-            drawFrac = 1f;
-        } else if (level <= mCriticalLevel) {
-            drawFrac = 0f;
-        }
-
-        final float levelTop = drawFrac == 1f ? mButtonFrame.top
-                : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
-
-        // define the battery shape
-        mShapePath.reset();
-        mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
-        mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
-        mShapePath.lineTo(mButtonFrame.right, mFrame.top);
-        mShapePath.lineTo(mFrame.right, mFrame.top);
-        mShapePath.lineTo(mFrame.right, mFrame.bottom);
-        mShapePath.lineTo(mFrame.left, mFrame.bottom);
-        mShapePath.lineTo(mFrame.left, mFrame.top);
-        mShapePath.lineTo(mButtonFrame.left, mFrame.top);
-        mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
-
-        if (mPluggedIn) {
-            // define the bolt shape
-            final float bl = mFrame.left + mFrame.width() / 4f;
-            final float bt = mFrame.top + mFrame.height() / 6f;
-            final float br = mFrame.right - mFrame.width() / 4f;
-            final float bb = mFrame.bottom - mFrame.height() / 10f;
-            if (mBoltFrame.left != bl || mBoltFrame.top != bt
-                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
-                mBoltFrame.set(bl, bt, br, bb);
-                mBoltPath.reset();
-                mBoltPath.moveTo(
-                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
-                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
-                for (int i = 2; i < mBoltPoints.length; i += 2) {
-                    mBoltPath.lineTo(
-                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
-                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
-                }
-                mBoltPath.lineTo(
-                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
-                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
-            }
-
-            float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
-            boltPct = Math.min(Math.max(boltPct, 0), 1);
-            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
-                // draw the bolt if opaque
-                c.drawPath(mBoltPath, mBoltPaint);
-            } else {
-                // otherwise cut the bolt out of the overall shape
-                mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
-            }
-        } else if (mPowerSaveEnabled) {
-            // define the plus shape
-            final float pw = mFrame.width() * 2 / 3;
-            final float pl = mFrame.left + (mFrame.width() - pw) / 2;
-            final float pt = mFrame.top + (mFrame.height() - pw) / 2;
-            final float pr = mFrame.right - (mFrame.width() - pw) / 2;
-            final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
-            if (mPlusFrame.left != pl || mPlusFrame.top != pt
-                    || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
-                mPlusFrame.set(pl, pt, pr, pb);
-                mPlusPath.reset();
-                mPlusPath.moveTo(
-                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
-                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
-                for (int i = 2; i < mPlusPoints.length; i += 2) {
-                    mPlusPath.lineTo(
-                            mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
-                            mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
-                }
-                mPlusPath.lineTo(
-                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
-                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
-            }
-
-            float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
-            boltPct = Math.min(Math.max(boltPct, 0), 1);
-            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
-                // draw the bolt if opaque
-                c.drawPath(mPlusPath, mPlusPaint);
-            } else {
-                // otherwise cut the bolt out of the overall shape
-                mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
-            }
-        }
-
-        // compute percentage text
-        boolean pctOpaque = false;
-        float pctX = 0, pctY = 0;
-        String pctText = null;
-        if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
-            mTextPaint.setColor(getColorForLevel(level));
-            mTextPaint.setTextSize(height *
-                    (SINGLE_DIGIT_PERCENT ? 0.75f
-                            : (mLevel == 100 ? 0.38f : 0.5f)));
-            mTextHeight = -mTextPaint.getFontMetrics().ascent;
-            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
-            pctX = mWidth * 0.5f;
-            pctY = (mHeight + mTextHeight) * 0.47f;
-            pctOpaque = levelTop > pctY;
-            if (!pctOpaque) {
-                mTextPath.reset();
-                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
-                // cut the percentage text out of the overall shape
-                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
-            }
-        }
-
-        // draw the battery shape background
-        c.drawPath(mShapePath, mFramePaint);
-
-        // draw the battery shape, clipped to charging level
-        mFrame.top = levelTop;
-        mClipPath.reset();
-        mClipPath.addRect(mFrame,  Path.Direction.CCW);
-        mShapePath.op(mClipPath, Path.Op.INTERSECT);
-        c.drawPath(mShapePath, mBatteryPaint);
-
-        if (!mPluggedIn && !mPowerSaveEnabled) {
-            if (level <= mCriticalLevel) {
-                // draw the warning text
-                final float x = mWidth * 0.5f;
-                final float y = (mHeight + mWarningTextHeight) * 0.48f;
-                c.drawText(mWarningString, x, y, mWarningTextPaint);
-            } else if (pctOpaque) {
-                // draw the percentage text
-                c.drawText(pctText, pctX, pctY, mTextPaint);
-            }
-        }
-    }
-
-    // Some stuff required by Drawable.
-    @Override
-    public void setAlpha(int alpha) {
-    }
-
-    @Override
-    public void setColorFilter(@Nullable ColorFilter colorFilter) {
-        mFramePaint.setColorFilter(colorFilter);
-        mBatteryPaint.setColorFilter(colorFilter);
-        mWarningTextPaint.setColorFilter(colorFilter);
-        mTextPaint.setColorFilter(colorFilter);
-        mBoltPaint.setColorFilter(colorFilter);
-        mPlusPaint.setColorFilter(colorFilter);
-    }
-
-    @Override
-    public int getOpacity() {
-        return 0;
+        setPowerSave(mBatteryController.isPowerSave());
     }
 
     private final class SettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 29a8da0..69e3874 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -16,18 +16,29 @@
 package com.android.systemui;
 
 import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.View;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
 
 public class BatteryMeterView extends ImageView implements
-        BatteryController.BatteryStateChangeCallback, TunerService.Tunable {
+        BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
 
     private final BatteryMeterDrawable mDrawable;
     private final String mSlotBattery;
@@ -77,6 +88,7 @@
         mBatteryController.addCallback(this);
         mDrawable.startListening();
         Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+        Dependency.get(ConfigurationController.class).addCallback(this);
     }
 
     @Override
@@ -85,6 +97,7 @@
         mBatteryController.removeCallback(this);
         mDrawable.stopListening();
         Dependency.get(TunerService.class).removeTunable(this);
+        Dependency.get(ConfigurationController.class).removeCallback(this);
     }
 
     @Override
@@ -99,8 +112,35 @@
 
     }
 
-    public void setDarkIntensity(float f) {
-        mDrawable.setDarkIntensity(f);
+    @Override
+    public void onDensityOrFontScaleChanged() {
+        scaleBatteryMeterViews();
+    }
+
+    /**
+     * Looks up the scale factor for status bar icons and scales the battery view by that amount.
+     */
+    private void scaleBatteryMeterViews() {
+        Resources res = getContext().getResources();
+        TypedValue typedValue = new TypedValue();
+
+        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
+        float iconScaleFactor = typedValue.getFloat();
+
+        int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
+        int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
+        int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
+
+        LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
+                (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
+        scaledLayoutParams.setMarginsRelative(0, 0, 0, marginBottom);
+
+        setLayoutParams(scaledLayoutParams);
+    }
+
+    @Override
+    public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+        mDrawable.setDarkIntensity(DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0);
     }
 
     public void setRawColors(int fgColor, int bgColor) {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index e1f3176..8d46b43 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -23,10 +23,16 @@
 import android.util.ArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
+import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryControllerImpl;
@@ -34,6 +40,8 @@
 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastControllerImpl;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -59,6 +67,7 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.leak.LeakDetector;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -84,18 +93,19 @@
     /**
      * Key for getting a background Looper for background work.
      */
-    public static final String BG_LOOPER = "background_loooper";
+    public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>("background_looper");
     /**
      * Key for getting a Handler for receiving time tick broadcasts on.
      */
-    public static final String TIME_TICK_HANDLER = "time_tick_handler";
+    public static final DependencyKey<Handler> TIME_TICK_HANDLER =
+            new DependencyKey<>("time_tick_handler");
     /**
      * Generic handler on the main thread.
      */
-    public static final String MAIN_HANDLER = "main_handler";
+    public static final DependencyKey<Handler> MAIN_HANDLER = new DependencyKey<>("main_handler");
 
-    private final ArrayMap<String, Object> mDependencies = new ArrayMap<>();
-    private final ArrayMap<String, DependencyProvider> mProviders = new ArrayMap<>();
+    private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
+    private final ArrayMap<Object, DependencyProvider> mProviders = new ArrayMap<>();
 
     @Override
     public void start() {
@@ -114,75 +124,89 @@
             return thread.getLooper();
         });
         mProviders.put(MAIN_HANDLER, () -> new Handler(Looper.getMainLooper()));
-        mProviders.put(ActivityStarter.class.getName(), () -> new ActivityStarterDelegate());
-        mProviders.put(ActivityStarterDelegate.class.getName(), () ->
+        mProviders.put(ActivityStarter.class, () -> new ActivityStarterDelegate());
+        mProviders.put(ActivityStarterDelegate.class, () ->
                 getDependency(ActivityStarter.class));
 
-        mProviders.put(BluetoothController.class.getName(), () ->
+        mProviders.put(BluetoothController.class, () ->
                 new BluetoothControllerImpl(mContext, getDependency(BG_LOOPER)));
 
-        mProviders.put(LocationController.class.getName(), () ->
+        mProviders.put(LocationController.class, () ->
                 new LocationControllerImpl(mContext, getDependency(BG_LOOPER)));
 
-        mProviders.put(RotationLockController.class.getName(), () ->
+        mProviders.put(RotationLockController.class, () ->
                 new RotationLockControllerImpl(mContext));
 
-        mProviders.put(NetworkController.class.getName(), () ->
+        mProviders.put(NetworkController.class, () ->
                 new NetworkControllerImpl(mContext, getDependency(BG_LOOPER),
                         getDependency(DeviceProvisionedController.class)));
 
-        mProviders.put(ZenModeController.class.getName(), () ->
+        mProviders.put(ZenModeController.class, () ->
                 new ZenModeControllerImpl(mContext, getDependency(MAIN_HANDLER)));
 
-        mProviders.put(HotspotController.class.getName(), () ->
+        mProviders.put(HotspotController.class, () ->
                 new HotspotControllerImpl(mContext));
 
-        mProviders.put(CastController.class.getName(), () ->
+        mProviders.put(CastController.class, () ->
                 new CastControllerImpl(mContext));
 
-        mProviders.put(FlashlightController.class.getName(), () ->
+        mProviders.put(FlashlightController.class, () ->
                 new FlashlightControllerImpl(mContext));
 
-        mProviders.put(KeyguardMonitor.class.getName(), () ->
+        mProviders.put(KeyguardMonitor.class, () ->
                 new KeyguardMonitorImpl(mContext));
 
-        mProviders.put(UserSwitcherController.class.getName(), () ->
+        mProviders.put(UserSwitcherController.class, () ->
                 new UserSwitcherController(mContext, getDependency(KeyguardMonitor.class),
                         getDependency(MAIN_HANDLER), getDependency(ActivityStarter.class)));
 
-        mProviders.put(UserInfoController.class.getName(), () ->
+        mProviders.put(UserInfoController.class, () ->
                 new UserInfoControllerImpl(mContext));
 
-        mProviders.put(BatteryController.class.getName(), () ->
+        mProviders.put(BatteryController.class, () ->
                 new BatteryControllerImpl(mContext));
 
-        mProviders.put(ManagedProfileController.class.getName(), () ->
+        mProviders.put(ManagedProfileController.class, () ->
                 new ManagedProfileControllerImpl(mContext));
 
-        mProviders.put(NextAlarmController.class.getName(), () ->
+        mProviders.put(NextAlarmController.class, () ->
                 new NextAlarmControllerImpl(mContext));
 
-        mProviders.put(DataSaverController.class.getName(), () ->
+        mProviders.put(DataSaverController.class, () ->
                 get(NetworkController.class).getDataSaverController());
 
-        mProviders.put(AccessibilityController.class.getName(), () ->
+        mProviders.put(AccessibilityController.class, () ->
                 new AccessibilityController(mContext));
 
-        mProviders.put(DeviceProvisionedController.class.getName(), () ->
+        mProviders.put(DeviceProvisionedController.class, () ->
                 new DeviceProvisionedControllerImpl(mContext));
 
-        mProviders.put(PluginManager.class.getName(), () ->
+        mProviders.put(PluginManager.class, () ->
                 new PluginManager(mContext));
 
-        mProviders.put(AssistManager.class.getName(), () ->
+        mProviders.put(AssistManager.class, () ->
                 new AssistManager(getDependency(DeviceProvisionedController.class), mContext));
 
-        mProviders.put(SecurityController.class.getName(), () ->
+        mProviders.put(SecurityController.class, () ->
                 new SecurityControllerImpl(mContext));
 
-        mProviders.put(TunerService.class.getName(), () ->
+        mProviders.put(LeakDetector.class, LeakDetector::create);
+
+        mProviders.put(TunerService.class, () ->
                 new TunerService(mContext));
 
+        mProviders.put(StatusBarWindowManager.class, () ->
+                new StatusBarWindowManager(mContext));
+
+        mProviders.put(DarkIconDispatcher.class, () ->
+                new DarkIconDispatcherImpl(mContext));
+
+        mProviders.put(ConfigurationController.class, () ->
+                new ConfigurationControllerImpl(mContext));
+
+        mProviders.put(StatusBarIconController.class, () ->
+                new StatusBarIconControllerImpl(mContext));
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
     }
@@ -203,20 +227,28 @@
     }
 
     protected final <T> T getDependency(Class<T> cls) {
-        return getDependency(cls.getName());
+        return getDependencyInner(cls);
     }
 
-    protected final <T> T getDependency(String cls) {
-        T obj = (T) mDependencies.get(cls);
+    protected final <T> T getDependency(DependencyKey<T> key) {
+        return getDependencyInner(key);
+    }
+
+    private <T> T getDependencyInner(Object key) {
+        @SuppressWarnings("unchecked")
+        T obj = (T) mDependencies.get(key);
         if (obj == null) {
-            obj = createDependency(cls);
-            mDependencies.put(cls, obj);
+            obj = createDependency(key);
+            mDependencies.put(key, obj);
         }
         return obj;
     }
 
     @VisibleForTesting
-    protected <T> T createDependency(String cls) {
+    protected <T> T createDependency(Object cls) {
+        Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>);
+
+        @SuppressWarnings("unchecked")
         DependencyProvider<T> provider = mProviders.get(cls);
         if (provider == null) {
             throw new IllegalArgumentException("Unsupported dependency " + cls);
@@ -242,10 +274,23 @@
     }
 
     public static <T> T get(Class<T> cls) {
-        return sDependency.getDependency(cls.getName());
+        return sDependency.getDependency(cls);
     }
 
-    public static <T> T get(String cls) {
+    public static <T> T get(DependencyKey<T> cls) {
         return sDependency.getDependency(cls);
     }
+
+    public static final class DependencyKey<V> {
+        private final String mDisplayName;
+
+        public DependencyKey(String displayName) {
+            mDisplayName = displayName;
+        }
+
+        @Override
+        public String toString() {
+            return mDisplayName;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index a9ac2d9..e5bda7e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -27,6 +27,7 @@
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.systemui.fragments.FragmentService;
@@ -43,6 +44,7 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarWindowManager;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.usb.StorageNotification;
 import com.android.systemui.util.NotificationChannels;
@@ -87,6 +89,7 @@
      * above.
      */
     private final Class<?>[] SERVICES_PER_USER = new Class[] {
+            Dependency.class,
             Recents.class,
             PipUI.class
     };
@@ -148,7 +151,6 @@
      * Makes sure that all the SystemUI services are running. If they are already running, this is a
      * no-op. This is needed to conditinally start all the services, as we only need to have it in
      * the main process.
-     *
      * <p>This method must only be called from the main thread.</p>
      */
     public void startServicesIfNeeded() {
@@ -159,7 +161,6 @@
      * Ensures that all the Secondary user SystemUI services are running. If they are already
      * running, this is a no-op. This is needed to conditinally start all the services, as we only
      * need to have it in the main process.
-     *
      * <p>This method must only be called from the main thread.</p>
      */
     void startSecondaryUserServicesIfNeeded() {
@@ -183,7 +184,7 @@
         Log.v(TAG, "Starting SystemUI services for user " +
                 Process.myUserHandle().getIdentifier() + ".");
         final int N = services.length;
-        for (int i=0; i<N; i++) {
+        for (int i = 0; i < N; i++) {
             Class<?> cl = services[i];
             if (DEBUG) Log.d(TAG, "loading: " + cl);
             try {
@@ -206,15 +207,34 @@
         }
         Dependency.get(PluginManager.class).addPluginListener(OverlayPlugin.ACTION,
                 new PluginListener<OverlayPlugin>() {
-            @Override
-            public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
-                StatusBar statusBar = getComponent(StatusBar.class);
-                if (statusBar != null) {
-                    plugin.setup(statusBar.getStatusBarWindow(),
-                            statusBar.getNavigationBarView());
-                }
-            }
-        }, OverlayPlugin.VERSION, true /* Allow multiple plugins */);
+                    private ArraySet<OverlayPlugin> mOverlays;
+
+                    @Override
+                    public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
+                        StatusBar statusBar = getComponent(StatusBar.class);
+                        if (statusBar != null) {
+                            plugin.setup(statusBar.getStatusBarWindow(),
+                                    statusBar.getNavigationBarView());
+                        }
+                        // Lazy init.
+                        if (mOverlays == null) mOverlays = new ArraySet<>();
+                        if (plugin.holdStatusBarOpen()) {
+                            mOverlays.add(plugin);
+                            Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
+                                    mOverlays.forEach(o -> o.setCollapseDesired(b)));
+                            Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
+                                    mOverlays.size() != 0);
+
+                        }
+                    }
+
+                    @Override
+                    public void onPluginDisconnected(OverlayPlugin plugin) {
+                        mOverlays.remove(plugin);
+                        Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
+                                mOverlays.size() != 0);
+                    }
+                }, OverlayPlugin.VERSION, true /* Allow multiple plugins */);
 
         mServicesStarted = true;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 1ff0701..411fd3d 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -113,6 +113,6 @@
         return null;
     }
 
-    public void injectDependencies(ArrayMap<String, DependencyProvider> providers,
+    public void injectDependencies(ArrayMap<Object, DependencyProvider> providers,
             Context context) { }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index aa22618..7c15096 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.doze;
 
+import android.app.AlarmManager;
 import android.app.Application;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -25,10 +26,7 @@
 import android.os.SystemClock;
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIApplication;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.doze.DozeProvider;
 import com.android.systemui.statusbar.phone.DozeParameters;
 
@@ -45,6 +43,7 @@
         Context context = dozeService;
         SensorManager sensorManager = context.getSystemService(SensorManager.class);
         PowerManager powerManager = context.getSystemService(PowerManager.class);
+        AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
 
         DozeHost host = getHost(dozeService);
         AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
@@ -57,7 +56,7 @@
         machine.setParts(new DozeMachine.Part[]{
                 createDozeTriggers(context, sensorManager, host, config, params, handler, wakeLock,
                         machine),
-                createDozeUi(context, host, wakeLock, machine),
+                createDozeUi(context, host, wakeLock, machine, handler, alarmManager),
         });
 
         return machine;
@@ -72,7 +71,7 @@
     }
 
     private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
-            DozeMachine machine) {
+            DozeMachine machine, Handler handler, AlarmManager alarmManager) {
         if (mDozePlugin != null) {
             DozeProvider.DozeUi dozeUi = mDozePlugin.provideDozeUi(context,
                     pluginMachine(context, machine, host),
@@ -82,7 +81,7 @@
                         pluginState(newState));
             };
         } else {
-            return new DozeUi(context, machine, wakeLock, host);
+            return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 00d2298..f3fb1ef 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -30,15 +30,12 @@
     void stopDozing();
     void dozeTimeTick();
     boolean isPowerSaveActive();
-    boolean isNotificationLightOn();
     boolean isPulsingBlocked();
 
     void startPendingIntentDismissingKeyguard(PendingIntent intent);
 
     interface Callback {
-        default void onNewNotifications() {}
         default void onNotificationHeadsUp() {}
-        default void onNotificationLight(boolean on) {}
         default void onPowerSaveChanged(boolean active) {}
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 95e49ce..76e0283 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -16,7 +16,13 @@
 
 package com.android.systemui.doze;
 
+import android.app.AlarmManager;
 import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 
 /**
  * The policy controlling doze.
@@ -24,16 +30,25 @@
 public class DozeUi implements DozeMachine.Part {
 
     private final Context mContext;
+    private final AlarmManager mAlarmManager;
     private final DozeHost mHost;
-    private DozeFactory.WakeLock mWakeLock;
-    private DozeMachine mMachine;
+    private final Handler mHandler;
+    private final DozeFactory.WakeLock mWakeLock;
+    private final DozeMachine mMachine;
+    private final AlarmManager.OnAlarmListener mTimeTick;
 
-    public DozeUi(Context context, DozeMachine machine, DozeFactory.WakeLock wakeLock,
-            DozeHost host) {
+    private boolean mTimeTickScheduled = false;
+
+    public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
+            DozeFactory.WakeLock wakeLock, DozeHost host, Handler handler) {
         mContext = context;
+        mAlarmManager = alarmManager;
         mMachine = machine;
         mWakeLock = wakeLock;
         mHost = host;
+        mHandler = handler;
+
+        mTimeTick = this::onTimeTick;
     }
 
     private void pulseWhileDozing(int reason) {
@@ -54,6 +69,12 @@
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         switch (newState) {
+            case DOZE_AOD:
+                scheduleTimeTick();
+                break;
+            case DOZE:
+                unscheduleTimeTick();
+                break;
             case DOZE_REQUEST_PULSE:
                 pulseWhileDozing(DozeLog.PULSE_REASON_NOTIFICATION /* TODO */);
                 break;
@@ -62,7 +83,52 @@
                 break;
             case FINISH:
                 mHost.stopDozing();
+                unscheduleTimeTick();
                 break;
         }
     }
+
+    private void scheduleTimeTick() {
+        if (mTimeTickScheduled) {
+            return;
+        }
+
+        long delta = roundToNextMinute(System.currentTimeMillis()) - System.currentTimeMillis();
+        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + delta, "doze_time_tick", mTimeTick, mHandler);
+
+        mTimeTickScheduled = true;
+    }
+
+    private void unscheduleTimeTick() {
+        if (!mTimeTickScheduled) {
+            return;
+        }
+        mAlarmManager.cancel(mTimeTick);
+    }
+
+    private long roundToNextMinute(long timeInMillis) {
+        Calendar calendar = GregorianCalendar.getInstance();
+        calendar.setTimeInMillis(timeInMillis);
+        calendar.set(Calendar.MILLISECOND, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.add(Calendar.MINUTE, 1);
+
+        return calendar.getTimeInMillis();
+    }
+
+    private void onTimeTick() {
+        if (!mTimeTickScheduled) {
+            // Alarm was canceled, but we still got the callback. Ignore.
+            return;
+        }
+
+        mHost.dozeTimeTick();
+
+        // Keep wakelock until a frame has been pushed.
+        mHandler.post(mWakeLock.wrap(() -> {}));
+
+        mTimeTickScheduled = false;
+        scheduleTimeTick();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 50506a9..0c6bf52 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -97,7 +97,7 @@
         return p;
     }
 
-    public void addTagListener(String tag, FragmentListener listener) {
+    public FragmentHostManager addTagListener(String tag, FragmentListener listener) {
         ArrayList<FragmentListener> listeners = mListeners.get(tag);
         if (listeners == null) {
             listeners = new ArrayList<>();
@@ -108,6 +108,7 @@
         if (current != null && current.getView() != null) {
             listener.onFragmentViewCreated(tag, current);
         }
+        return this;
     }
 
     // Shouldn't generally be needed, included for completeness sake.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 99c8c6b..cbe822f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1956,11 +1956,11 @@
     }
 
     public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
-            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
+            ViewGroup container,
             ScrimController scrimController,
             FingerprintUnlockController fingerprintUnlockController) {
         mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container,
-                statusBarWindowManager, scrimController, fingerprintUnlockController,
+                scrimController, fingerprintUnlockController,
                 mDismissCallbackRegistry);
         return mStatusBarKeyguardViewManager;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
index e182176..0259e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
@@ -17,22 +17,22 @@
 package com.android.systemui.pip.phone;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.TouchDelegate;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
+import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.widget.FrameLayout;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 
 public class PipDismissViewController {
 
@@ -68,8 +68,10 @@
     public void createDismissTarget() {
         if (mDismissView == null) {
             // Determine sizes for the gradient
-            Point windowSize = new Point();
-            mWindowManager.getDefaultDisplay().getSize(windowSize);
+            final Rect stableInsets = new Rect();
+            SystemServicesProxy.getInstance(mContext).getStableInsets(stableInsets);
+            final Point windowSize = new Point();
+            mWindowManager.getDefaultDisplay().getRealSize(windowSize);
             mMinHeight = windowSize.y * DISMISS_GRADIENT_MIN_HEIGHT_PERCENT;
             mMaxHeight = windowSize.y * DISMISS_GRADIENT_MAX_HEIGHT_PERCENT;
 
@@ -77,13 +79,16 @@
             LayoutInflater inflater = LayoutInflater.from(mContext);
             mDismissView = inflater.inflate(R.layout.pip_dismiss_view, null);
             mGradientView = mDismissView.findViewById(R.id.gradient_view);
-            FrameLayout.LayoutParams glp = (android.widget.FrameLayout.LayoutParams) mGradientView
-                    .getLayoutParams();
+            FrameLayout.LayoutParams glp =
+                    (FrameLayout.LayoutParams) mGradientView.getLayoutParams();
             glp.height = (int) mMaxHeight;
             mGradientView.setLayoutParams(glp);
             mGradientView.setPivotY(windowSize.y);
             mGradientView.setScaleY(mMaxHeight / mMinHeight); // Set to min height via scaling
             mDismissContainer = mDismissView.findViewById(R.id.pip_dismiss_container);
+            FrameLayout.LayoutParams clp =
+                    (FrameLayout.LayoutParams) mDismissContainer.getLayoutParams();
+            clp.bottomMargin = stableInsets.bottom;
             mDismissContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() {
                 @Override
                 public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -95,15 +100,16 @@
             });
 
             // Add the target to the window
-            WindowManager.LayoutParams lp =  new WindowManager.LayoutParams(
-                    windowSize.x,
-                    (int) mMaxHeight,
-                    WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG,
-                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                            | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+            LayoutParams lp =  new LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, (int) mMaxHeight,
+                    0, windowSize.y - (int) mMaxHeight,
+                    LayoutParams.TYPE_SYSTEM_DIALOG,
+                    LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                            | LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                            | LayoutParams.FLAG_NOT_TOUCHABLE
+                            | LayoutParams.FLAG_NOT_FOCUSABLE,
                     PixelFormat.TRANSLUCENT);
-            lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+            lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
             mWindowManager.addView(mDismissView, lp);
         }
         mDismissView.animate().cancel();
@@ -135,7 +141,7 @@
                     .withEndAction(new Runnable() {
                         @Override
                         public void run() {
-                            mWindowManager.removeView(mDismissView);
+                            mWindowManager.removeViewImmediate(mDismissView);
                             mDismissView = null;
                         }
                     })
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 3df557d..f59b2a4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -16,20 +16,16 @@
 
 package com.android.systemui.pip.phone;
 
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.app.ActivityManager;
-import android.app.ActivityManager.StackInfo;
-import android.app.ActivityOptions;
 import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Log;
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
@@ -94,7 +90,7 @@
                 }
             }
             if (expandPipToFullscreen) {
-                mTouchHandler.expandPinnedStackToFullscreen();
+                mTouchHandler.getMotionHelper().expandPip();
             } else {
                 Log.w(TAG, "Can not expand PiP to fullscreen via intent from the same package.");
             }
@@ -114,28 +110,31 @@
         }
 
         @Override
-        public void onBoundsChanged(boolean adjustedForIme) {
-            // Do nothing
-        }
-
-        @Override
-        public void onActionsChanged(ParceledListSlice actions) {
+        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             mHandler.post(() -> {
-                mMenuController.setAppActions(actions);
+                mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
             });
         }
 
         @Override
         public void onMinimizedStateChanged(boolean isMinimized) {
             mHandler.post(() -> {
-                mTouchHandler.onMinimizedStateChanged(isMinimized);
+                mTouchHandler.setMinimizedState(isMinimized, true /* fromController */);
             });
         }
 
         @Override
-        public void onSnapToEdgeStateChanged(boolean isSnapToEdge) {
+        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+                boolean fromImeAdjustement) {
             mHandler.post(() -> {
-                mTouchHandler.onSnapToEdgeStateChanged(isSnapToEdge);
+                mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, fromImeAdjustement);
+            });
+        }
+
+        @Override
+        public void onActionsChanged(ParceledListSlice actions) {
+            mHandler.post(() -> {
+                mMenuController.setAppActions(actions);
             });
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index d96baa6..3a4caa9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -16,16 +16,22 @@
 
 package com.android.systemui.pip.phone;
 
+import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
+
 import android.app.IActivityManager;
+import android.app.PendingIntent;
 import android.app.RemoteAction;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.graphics.drawable.Icon;
 import android.media.session.MediaController;
-import android.media.session.MediaController.TransportControls;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
+import android.os.UserHandle;
 
 import com.android.systemui.R;
 
@@ -40,6 +46,9 @@
  */
 public class PipMediaController {
 
+    private static final String ACTION_PLAY = "com.android.systemui.pip.phone.PLAY";
+    private static final String ACTION_PAUSE = "com.android.systemui.pip.phone.PAUSE";
+
     /**
      * A listener interface to receive notification on changes to the media actions.
      */
@@ -59,12 +68,22 @@
     private RemoteAction mPauseAction;
     private RemoteAction mPlayAction;
 
+    private BroadcastReceiver mPlayPauseActionReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (action.equals(ACTION_PLAY)) {
+                mMediaController.getTransportControls().play();
+            } else if (action.equals(ACTION_PAUSE)) {
+                mMediaController.getTransportControls().pause();
+            }
+        }
+    };
+
     private MediaController.Callback mPlaybackChangedListener = new MediaController.Callback() {
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
-            if (!mListeners.isEmpty()) {
-                notifyActionsChanged(getMediaActions());
-            }
+            notifyActionsChanged();
         }
     };
 
@@ -73,6 +92,10 @@
     public PipMediaController(Context context, IActivityManager activityManager) {
         mContext = context;
         mActivityManager = activityManager;
+        IntentFilter mediaControlFilter = new IntentFilter();
+        mediaControlFilter.addAction(ACTION_PLAY);
+        mediaControlFilter.addAction(ACTION_PAUSE);
+        mContext.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter);
 
         createMediaActions();
         mMediaSessionManager =
@@ -121,9 +144,9 @@
         boolean isPlaying = MediaSession.isActiveState(state);
         long actions = mMediaController.getPlaybackState().getActions();
         if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) {
-            mediaActions.add(mPauseAction);
-        } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) {
             mediaActions.add(mPlayAction);
+        } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) {
+            mediaActions.add(mPauseAction);
         }
         return mediaActions;
     }
@@ -135,12 +158,14 @@
         String pauseDescription = mContext.getString(R.string.pip_pause);
         mPauseAction = new RemoteAction(Icon.createWithResource(mContext,
                 R.drawable.ic_pause_white_24dp), pauseDescription, pauseDescription,
-                action -> mMediaController.getTransportControls().pause());
+                        PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PAUSE),
+                                FLAG_UPDATE_CURRENT));
 
         String playDescription = mContext.getString(R.string.pip_play);
         mPlayAction = new RemoteAction(Icon.createWithResource(mContext,
                 R.drawable.ic_play_arrow_white_24dp), playDescription, playDescription,
-                action -> mMediaController.getTransportControls().play());
+                        PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PLAY),
+                                FLAG_UPDATE_CURRENT));
     }
 
     /**
@@ -175,9 +200,7 @@
             if (controller != null) {
                 controller.registerCallback(mPlaybackChangedListener);
             }
-            if (!mListeners.isEmpty()) {
-                notifyActionsChanged(getMediaActions());
-            }
+            notifyActionsChanged();
 
             // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV)
         }
@@ -186,8 +209,9 @@
     /**
      * Notifies all listeners that the actions have changed.
      */
-    private void notifyActionsChanged(List<RemoteAction> actions) {
+    private void notifyActionsChanged() {
         if (!mListeners.isEmpty()) {
+            List<RemoteAction> actions = getMediaActions();
             mListeners.forEach(l -> l.onMediaActionsChanged(actions));
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 438b8dd..9066977 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.PendingIntent.CanceledException;
 import android.app.RemoteAction;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
@@ -258,7 +259,11 @@
                     }, mHandler);
                     actionView.setContentDescription(action.getContentDescription());
                     actionView.setOnClickListener(v -> {
-                        action.sendActionInvoked();
+                        try {
+                            action.getActionIntent().send();
+                        } catch (CanceledException e) {
+                            Log.w(TAG, "Failed to send action", e);
+                        }
                     });
                     actionsGroup.addView(actionView);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
new file mode 100644
index 0000000..fb3ed44
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.pip.phone;
+
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+
+import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
+import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.ActivityManager.StackInfo;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.animation.Interpolator;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.statusbar.FlingAnimationUtils;
+
+/**
+ * A helper to animate and manipulate the PiP.
+ */
+public class PipMotionHelper {
+
+    private static final String TAG = "PipMotionHelper";
+
+    private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
+
+    private static final int DEFAULT_MOVE_STACK_DURATION = 225;
+    private static final int SNAP_STACK_DURATION = 225;
+    private static final int DISMISS_STACK_DURATION = 375;
+    private static final int SHRINK_STACK_FROM_MENU_DURATION = 175;
+    private static final int EXPAND_STACK_TO_MENU_DURATION = 175;
+    private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 225;
+    private static final int MINIMIZE_STACK_MAX_DURATION = 200;
+
+    // The fraction of the stack width that the user has to drag offscreen to minimize the PiP
+    private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.2f;
+
+    private Context mContext;
+    private IActivityManager mActivityManager;
+    private Handler mHandler;
+
+    private PipSnapAlgorithm mSnapAlgorithm;
+    private FlingAnimationUtils mFlingAnimationUtils;
+
+    private final Rect mBounds = new Rect();
+    private final Rect mStableInsets = new Rect();
+
+    private ValueAnimator mBoundsAnimator = null;
+    private ValueAnimator.AnimatorUpdateListener mUpdateBoundsListener =
+            new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    mBounds.set((Rect) animation.getAnimatedValue());
+                }
+            };
+
+    public PipMotionHelper(Context context, IActivityManager activityManager,
+            PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) {
+        mContext = context;
+        mHandler = BackgroundThread.getHandler();
+        mActivityManager = activityManager;
+        mSnapAlgorithm = snapAlgorithm;
+        mFlingAnimationUtils = flingAnimationUtils;
+        onConfigurationChanged();
+    }
+
+    /**
+     * Updates whenever the configuration changes.
+     */
+    void onConfigurationChanged() {
+        mSnapAlgorithm.onConfigurationChanged();
+        SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+    }
+
+    /**
+     * Synchronizes the current bounds with the pinned stack.
+     */
+    void synchronizePinnedStackBounds() {
+        cancelAnimations();
+        try {
+            StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+            if (stackInfo != null) {
+                mBounds.set(stackInfo.bounds);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get pinned stack bounds");
+        }
+    }
+
+    /**
+     * Tries to the move the pinned stack to the given {@param bounds}.
+     */
+    void movePip(Rect toBounds) {
+        cancelAnimations();
+        resizePipUnchecked(toBounds);
+        mBounds.set(toBounds);
+    }
+
+    /**
+     * Resizes the pinned stack back to fullscreen.
+     */
+    void expandPip() {
+        cancelAnimations();
+        mHandler.post(() -> {
+            try {
+                mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */,
+                        true /* allowResizeInDockedMode */, true /* preserveWindows */,
+                        true /* animate */, EXPAND_STACK_TO_FULLSCREEN_DURATION);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error showing PiP menu activity", e);
+            }
+        });
+    }
+
+    /**
+     * Dismisses the pinned stack.
+     */
+    void dismissPip() {
+        cancelAnimations();
+        mHandler.post(() -> {
+            try {
+                mActivityManager.removeStack(PINNED_STACK_ID);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to remove PiP", e);
+            }
+        });
+    }
+
+    /**
+     * @return the PiP bounds.
+     */
+    Rect getBounds() {
+        return mBounds;
+    }
+
+    /**
+     * @return the closest minimized PiP bounds.
+     */
+    Rect getClosestMinimizedBounds(Rect stackBounds, Rect movementBounds) {
+        Point displaySize = new Point();
+        mContext.getDisplay().getRealSize(displaySize);
+        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, stackBounds);
+        mSnapAlgorithm.applyMinimizedOffset(toBounds, movementBounds, displaySize, mStableInsets);
+        return toBounds;
+    }
+
+    /**
+     * @return whether the PiP at the current bounds should be minimized.
+     */
+    boolean shouldMinimizePip() {
+        Point displaySize = new Point();
+        mContext.getDisplay().getRealSize(displaySize);
+        if (mBounds.left < 0) {
+            float offscreenFraction = (float) -mBounds.left / mBounds.width();
+            return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+        } else if (mBounds.right > displaySize.x) {
+            float offscreenFraction = (float) (mBounds.right - displaySize.x) /
+                    mBounds.width();
+            return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Flings the minimized PiP to the closest minimized snap target.
+     */
+    Rect flingToMinimizedState(float velocityY, Rect movementBounds) {
+        cancelAnimations();
+        // We currently only allow flinging the minimized stack up and down, so just lock the
+        // movement bounds to the current stack bounds horizontally
+        movementBounds = new Rect(mBounds.left, movementBounds.top, mBounds.left,
+                movementBounds.bottom);
+        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
+                0 /* velocityX */, velocityY);
+        if (!mBounds.equals(toBounds)) {
+            mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
+                    mUpdateBoundsListener);
+            mFlingAnimationUtils.apply(mBoundsAnimator, 0,
+                    distanceBetweenRectOffsets(mBounds, toBounds),
+                    velocityY);
+            mBoundsAnimator.start();
+        }
+        return toBounds;
+    }
+
+    /**
+     * Animates the PiP to the minimized state, slightly offscreen.
+     */
+    Rect animateToClosestMinimizedState(Rect movementBounds,
+            final PipMenuActivityController menuController) {
+        cancelAnimations();
+        Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds);
+        if (!mBounds.equals(toBounds)) {
+            mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
+                    MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdateBoundsListener);
+            mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    menuController.hideMenu();
+                }
+            });
+            mBoundsAnimator.start();
+        }
+        return toBounds;
+    }
+
+    /**
+     * Flings the PiP to the closest snap target.
+     */
+    Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds) {
+        cancelAnimations();
+        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
+                velocityX, velocityY);
+        if (!mBounds.equals(toBounds)) {
+            mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
+                    mUpdateBoundsListener);
+            mFlingAnimationUtils.apply(mBoundsAnimator, 0,
+                    distanceBetweenRectOffsets(mBounds, toBounds),
+                    velocity);
+            mBoundsAnimator.start();
+        }
+        return toBounds;
+    }
+
+    /**
+     * Animates the PiP to the closest snap target.
+     */
+    Rect animateToClosestSnapTarget(Rect movementBounds) {
+        cancelAnimations();
+        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
+        if (!mBounds.equals(toBounds)) {
+            mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
+                    FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+            mBoundsAnimator.start();
+        }
+        return toBounds;
+    }
+
+    /**
+     * Animates the PiP to the expanded state to show the menu.
+     */
+    float animateToExpandedState(Rect expandedBounds, Rect movementBounds,
+            Rect expandedMovementBounds) {
+        float savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), movementBounds);
+        mSnapAlgorithm.applySnapFraction(expandedBounds, expandedMovementBounds, savedSnapFraction);
+        mBoundsAnimator = createAnimationToBounds(mBounds, expandedBounds,
+                EXPAND_STACK_TO_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+        mBoundsAnimator.start();
+        return savedSnapFraction;
+    }
+
+    /**
+     * Animates the PiP from the expanded state to the normal state after the menu is hidden.
+     */
+    void animateToUnexpandedState(Rect normalBounds, float savedSnapFraction,
+            Rect normalMovementBounds) {
+        if (savedSnapFraction >= 0f) {
+            mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction);
+            mBoundsAnimator = createAnimationToBounds(mBounds, normalBounds,
+                    SHRINK_STACK_FROM_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+            mBoundsAnimator.start();
+        } else {
+            animateToClosestSnapTarget(normalMovementBounds);
+        }
+    }
+
+    /**
+     * Animates the dismissal of the PiP over the dismiss target bounds.
+     */
+    Rect animateDismissFromDrag(Rect dismissBounds) {
+        cancelAnimations();
+        Rect toBounds = new Rect(dismissBounds.centerX(),
+                dismissBounds.centerY(),
+                dismissBounds.centerX() + 1,
+                dismissBounds.centerY() + 1);
+        mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, DISMISS_STACK_DURATION,
+                FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
+        mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                dismissPip();
+            }
+        });
+        mBoundsAnimator.start();
+        return toBounds;
+    }
+
+    /**
+     * Animates the PiP to some given bounds.
+     */
+    void animateToBounds(Rect toBounds) {
+        cancelAnimations();
+        if (!mBounds.equals(toBounds)) {
+            mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
+                    DEFAULT_MOVE_STACK_DURATION, FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
+            mBoundsAnimator.start();
+        }
+    }
+
+    /**
+     * Cancels all existing animations.
+     */
+    void cancelAnimations() {
+        if (mBoundsAnimator != null) {
+            mBoundsAnimator.cancel();
+            mBoundsAnimator = null;
+        }
+    }
+
+    /**
+     * Creates an animation to move the PiP to give given {@param toBounds}.
+     */
+    private ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds, int duration,
+            Interpolator interpolator, ValueAnimator.AnimatorUpdateListener updateListener) {
+        ValueAnimator anim = ValueAnimator.ofObject(RECT_EVALUATOR, fromBounds, toBounds);
+        anim.setDuration(duration);
+        anim.setInterpolator(interpolator);
+        anim.addUpdateListener((ValueAnimator animation) -> {
+            resizePipUnchecked((Rect) animation.getAnimatedValue());
+        });
+        if (updateListener != null) {
+            anim.addUpdateListener(updateListener);
+        }
+        return anim;
+    }
+
+    /**
+     * Directly resizes the PiP to the given {@param bounds}.
+     */
+    private void resizePipUnchecked(Rect toBounds) {
+        if (!toBounds.equals(mBounds)) {
+            mHandler.post(() -> {
+                try {
+                    mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
+                    mBounds.set(toBounds);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Could not move pinned stack to bounds: " + toBounds, e);
+                }
+            });
+        }
+    }
+
+    /**
+     * @return the distance between points {@param p1} and {@param p2}.
+     */
+    private float distanceBetweenRectOffsets(Rect r1, Rect r2) {
+        return PointF.length(r1.left - r2.left, r1.top - r2.top);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 10393c6..b3adee0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -16,21 +16,10 @@
 
 package com.android.systemui.pip.phone;
 
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
-import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
-import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.ActivityManager.StackInfo;
 import android.app.IActivityManager;
 import android.content.Context;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Handler;
@@ -47,8 +36,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.policy.PipMotionHelper;
 import com.android.internal.policy.PipSnapAlgorithm;
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -60,24 +47,15 @@
  */
 public class PipTouchHandler implements TunerService.Tunable {
     private static final String TAG = "PipTouchHandler";
-    private static final boolean DEBUG_ALLOW_OUT_OF_BOUNDS_STACK = false;
 
     // These values are used for metrics and should never change
     private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0;
     private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1;
 
     private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss";
-    private static final String TUNER_KEY_ALLOW_MINIMIZE = "pip_allow_minimize";
 
-    private static final int SNAP_STACK_DURATION = 225;
-    private static final int DISMISS_STACK_DURATION = 375;
-    private static final int EXPAND_STACK_DURATION = 225;
-    private static final int MINIMIZE_STACK_MAX_DURATION = 200;
     private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 200;
 
-    // The fraction of the stack width that the user has to drag offscreen to minimize the PIP
-    private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.2f;
-
     private final Context mContext;
     private final IActivityManager mActivityManager;
     private final IWindowManager mWindowManager;
@@ -86,34 +64,28 @@
     private IPinnedStackController mPinnedStackController;
 
     private PipInputEventReceiver mInputEventReceiver;
-    private PipMenuActivityController mMenuController;
-    private PipDismissViewController mDismissViewController;
+    private final PipMenuActivityController mMenuController;
+    private final PipDismissViewController mDismissViewController;
     private final PipSnapAlgorithm mSnapAlgorithm;
-    private PipMotionHelper mMotionHelper;
 
     // Allow dragging the PIP to a location to close it
     private boolean mEnableDragToDismiss = false;
-    // Allow the PIP to be "docked" slightly offscreen
-    private boolean mEnableMinimizing = true;
 
-    private final Rect mStableInsets = new Rect();
-    private final Rect mPinnedStackBounds = new Rect();
-    private final Rect mBoundedPinnedStackBounds = new Rect();
-    private ValueAnimator mPinnedStackBoundsAnimator = null;
-    private ValueAnimator.AnimatorUpdateListener mUpdatePinnedStackBoundsListener =
-            new AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            mPinnedStackBounds.set((Rect) animation.getAnimatedValue());
-        }
-    };
+    // The current movement bounds
+    private Rect mMovementBounds = new Rect();
+
+    // The reference bounds used to calculate the normal/expanded target bounds
+    private Rect mNormalBounds = new Rect();
+    private Rect mNormalMovementBounds = new Rect();
+    private Rect mExpandedBounds = new Rect();
+    private Rect mExpandedMovementBounds = new Rect();
 
     private Handler mHandler = new Handler();
     private Runnable mShowDismissAffordance = new Runnable() {
         @Override
         public void run() {
             if (mEnableDragToDismiss) {
-                mDismissViewController.showDismissTarget(mPinnedStackBounds);
+                mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
             }
         }
     };
@@ -121,13 +93,18 @@
     // Behaviour states
     private boolean mIsTappingThrough;
     private boolean mIsMinimized;
+    private boolean mIsMenuVisible;
+    private boolean mIsImeShowing;
+    private int mImeHeight;
+    private float mSavedSnapFraction = -1f;
 
     // Touch state
     private final PipTouchState mTouchState;
     private final FlingAnimationUtils mFlingAnimationUtils;
     private final PipTouchGesture[] mGestures;
+    private final PipMotionHelper mMotionHelper;
 
-    // Temporary vars
+    // Temp vars
     private final Rect mTmpBounds = new Rect();
 
     /**
@@ -160,32 +137,25 @@
     private class PipMenuListener implements PipMenuActivityController.Listener {
         @Override
         public void onPipMenuVisibilityChanged(boolean visible) {
-            if (!visible) {
-                mIsTappingThrough = false;
-                registerInputConsumer();
-            } else {
-                unregisterInputConsumer();
-            }
-            MetricsLogger.visibility(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
-                    visible);
+            setMenuVisibilityState(visible);
         }
 
         @Override
         public void onPipExpand() {
             if (!mIsMinimized) {
-                expandPinnedStackToFullscreen();
+                mMotionHelper.expandPip();
             }
         }
 
         @Override
         public void onPipMinimize() {
-            setMinimizedState(true);
-            animateToClosestMinimizedTarget();
+            setMinimizedStateInternal(true);
+            mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController);
         }
 
         @Override
         public void onPipDismiss() {
-            BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
+            mMotionHelper.dismissPip();
             MetricsLogger.action(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
                     METRIC_VALUE_DISMISSED_BY_TAP);
         }
@@ -208,13 +178,12 @@
         mGestures = new PipTouchGesture[] {
                 mDefaultMovementGesture
         };
-        mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler());
+        mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm,
+                mFlingAnimationUtils);
         registerInputConsumer();
-        setSnapToEdge(true);
 
         // Register any tuner settings changes
-        Dependency.get(TunerService.class).addTunable(this, TUNER_KEY_DRAG_TO_DISMISS,
-                TUNER_KEY_ALLOW_MINIMIZE);
+        Dependency.get(TunerService.class).addTunable(this, TUNER_KEY_DRAG_TO_DISMISS);
     }
 
     @Override
@@ -222,17 +191,12 @@
         if (newValue == null) {
             // Reset back to default
             mEnableDragToDismiss = false;
-            mEnableMinimizing = true;
-            setMinimizedState(false);
             return;
         }
         switch (key) {
             case TUNER_KEY_DRAG_TO_DISMISS:
                 mEnableDragToDismiss = Integer.parseInt(newValue) != 0;
                 break;
-            case TUNER_KEY_ALLOW_MINIMIZE:
-                mEnableMinimizing = Integer.parseInt(newValue) != 0;
-                break;
         }
     }
 
@@ -243,26 +207,70 @@
             registerInputConsumer();
         }
         if (mIsMinimized) {
-            setMinimizedState(false);
+            setMinimizedStateInternal(false);
         }
     }
 
     public void onConfigurationChanged() {
-        mSnapAlgorithm.onConfigurationChanged();
-        updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
+        mMotionHelper.onConfigurationChanged();
+        mMotionHelper.synchronizePinnedStackBounds();
     }
 
-    public void onMinimizedStateChanged(boolean isMinimized) {
-        if (mIsMinimized != isMinimized) {
-            MetricsLogger.action(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED,
-                    isMinimized);
+    public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+        mIsImeShowing = imeVisible;
+        mImeHeight = imeHeight;
+    }
+
+    public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+            boolean fromImeAdjustement) {
+        // Re-calculate the expanded bounds
+        mNormalBounds = normalBounds;
+        Rect normalMovementBounds = new Rect();
+        mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
+                mIsImeShowing ? mImeHeight : 0);
+        // TODO: Figure out the expanded size policy
+        mExpandedBounds = new Rect(normalBounds);
+        Rect expandedMovementBounds = new Rect();
+        mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
+                mIsImeShowing ? mImeHeight : 0);
+
+
+        // If this is from an IME adjustment, then we should move the PiP so that it is not occluded
+        // by the IME
+        if (fromImeAdjustement) {
+            if (mTouchState.isUserInteracting()) {
+                // Defer the update of the current movement bounds until after the user finishes
+                // touching the screen
+            } else {
+                final Rect bounds = new Rect(mMotionHelper.getBounds());
+                final Rect toMovementBounds = mIsMenuVisible
+                        ? expandedMovementBounds
+                        : normalMovementBounds;
+                if (mIsImeShowing) {
+                    // IME visible
+                    if (bounds.top == mMovementBounds.bottom) {
+                        // If the PIP is currently resting on top of the IME, then adjust it with
+                        // the hiding IME
+                        bounds.offsetTo(bounds.left, toMovementBounds.bottom);
+                    } else {
+                        bounds.offset(0, Math.min(0, toMovementBounds.bottom - bounds.top));
+                    }
+                } else {
+                    // IME hidden
+                    if (bounds.top == mMovementBounds.bottom) {
+                        // If the PIP is resting on top of the IME, then adjust it with the hiding IME
+                        bounds.offsetTo(bounds.left, toMovementBounds.bottom);
+                    }
+                }
+                mMotionHelper.animateToBounds(bounds);
+            }
         }
-        mIsMinimized = isMinimized;
-        mSnapAlgorithm.setMinimized(isMinimized);
-    }
 
-    public void onSnapToEdgeStateChanged(boolean isSnapToEdge) {
-        mSnapAlgorithm.setSnapToEdge(isSnapToEdge);
+        // Update the movement bounds after doing the calculations based on the old movement bounds
+        // above
+        mNormalMovementBounds = normalMovementBounds;
+        mExpandedMovementBounds = expandedMovementBounds;
+        updateMovementBounds();
     }
 
     private boolean handleTouchEvent(MotionEvent ev) {
@@ -276,20 +284,11 @@
 
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN: {
-                // Cancel any existing animations on the pinned stack
-                if (mPinnedStackBoundsAnimator != null) {
-                    mPinnedStackBoundsAnimator.cancel();
-                }
+                mMotionHelper.synchronizePinnedStackBounds();
 
-                updateBoundedPinnedStackBounds(true /* updatePinnedStackBounds */);
                 for (PipTouchGesture gesture : mGestures) {
                     gesture.onDown(mTouchState);
                 }
-                try {
-                    mPinnedStackController.setInInteractiveMode(true);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not set dragging state", e);
-                }
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -303,7 +302,7 @@
             case MotionEvent.ACTION_UP: {
                 // Update the movement bounds again if the state has changed since the user started
                 // dragging (ie. when the IME shows)
-                updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
+                updateMovementBounds();
 
                 for (PipTouchGesture gesture : mGestures) {
                     if (gesture.onUp(mTouchState)) {
@@ -314,11 +313,6 @@
                 // Fall through to clean up
             }
             case MotionEvent.ACTION_CANCEL: {
-                try {
-                    mPinnedStackController.setInInteractiveMode(false);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not set dragging state", e);
-                }
                 break;
             }
         }
@@ -326,16 +320,6 @@
     }
 
     /**
-     * @return whether the current touch state places the pip partially offscreen.
-     */
-    private boolean isDraggingOffscreen(PipTouchState touchState) {
-        PointF lastDelta = touchState.getLastTouchDelta();
-        PointF downDelta = touchState.getDownTouchDelta();
-        float left = mPinnedStackBounds.left + lastDelta.x;
-        return !(mBoundedPinnedStackBounds.left <= left && left <= mBoundedPinnedStackBounds.right);
-    }
-
-    /**
      * Registers the input consumer.
      */
     private void registerInputConsumer() {
@@ -374,27 +358,30 @@
     }
 
     /**
-     * Sets the snap-to-edge state and notifies the controller.
+     * Sets the minimized state.
      */
-    private void setSnapToEdge(boolean snapToEdge) {
-        onSnapToEdgeStateChanged(snapToEdge);
-
-        if (mPinnedStackController != null) {
-            try {
-                mPinnedStackController.setSnapToEdge(snapToEdge);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Could not set snap mode to edge", e);
-            }
-        }
+    void setMinimizedStateInternal(boolean isMinimized) {
+        setMinimizedState(isMinimized, false /* fromController */);
     }
 
     /**
-     * Sets the minimized state and notifies the controller.
+     * Sets the minimized state.
      */
-    private void setMinimizedState(boolean isMinimized) {
-        onMinimizedStateChanged(isMinimized);
+    void setMinimizedState(boolean isMinimized, boolean fromController) {
+        if (mIsMinimized != isMinimized) {
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED,
+                    isMinimized);
+        }
+        mIsMinimized = isMinimized;
+        mSnapAlgorithm.setMinimized(isMinimized);
 
-        if (mPinnedStackController != null) {
+        if (fromController) {
+            if (isMinimized) {
+                // Move the PiP to the new bounds immediately if minimized
+                mMotionHelper.movePip(mMotionHelper.getClosestMinimizedBounds(mNormalBounds,
+                        mMovementBounds));
+            }
+        } else if (mPinnedStackController != null) {
             try {
                 mPinnedStackController.setIsMinimized(isMinimized);
             } catch (RemoteException e) {
@@ -404,178 +391,43 @@
     }
 
     /**
-     * @return whether the given {@param pinnedStackBounds} indicates the PIP should be minimized.
+     * Sets the menu visibility.
      */
-    private boolean shouldMinimizedPinnedStack() {
-        Point displaySize = new Point();
-        mContext.getDisplay().getRealSize(displaySize);
-        if (mPinnedStackBounds.left < 0) {
-            float offscreenFraction = (float) -mPinnedStackBounds.left / mPinnedStackBounds.width();
-            return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
-        } else if (mPinnedStackBounds.right > displaySize.x) {
-            float offscreenFraction = (float) (mPinnedStackBounds.right - displaySize.x) /
-                    mPinnedStackBounds.width();
-            return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+    void setMenuVisibilityState(boolean isMenuVisible) {
+        if (!isMenuVisible) {
+            mIsTappingThrough = false;
+            registerInputConsumer();
         } else {
-            return false;
+            unregisterInputConsumer();
         }
-    }
+        MetricsLogger.visibility(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
+                isMenuVisible);
 
-    /**
-     * Flings the minimized PIP to the closest minimized snap target.
-     */
-    private void flingToMinimizedSnapTarget(float velocityY) {
-        // We currently only allow flinging the minimized stack up and down, so just lock the
-        // movement bounds to the current stack bounds horizontally
-        Rect movementBounds = new Rect(mPinnedStackBounds.left, mBoundedPinnedStackBounds.top,
-                mPinnedStackBounds.left, mBoundedPinnedStackBounds.bottom);
-        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mPinnedStackBounds,
-                0 /* velocityX */, velocityY);
-        if (!mPinnedStackBounds.equals(toBounds)) {
-            mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
-                    toBounds, 0, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
-            mFlingAnimationUtils.apply(mPinnedStackBoundsAnimator, 0,
-                    distanceBetweenRectOffsets(mPinnedStackBounds, toBounds),
-                    velocityY);
-            mPinnedStackBoundsAnimator.start();
-        }
-    }
-
-    /**
-     * Animates the PIP to the minimized state, slightly offscreen.
-     */
-    private void animateToClosestMinimizedTarget() {
-        Point displaySize = new Point();
-        mContext.getDisplay().getRealSize(displaySize);
-        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
-                mPinnedStackBounds);
-        mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize,
-                mStableInsets);
-        mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
-                toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN,
-                mUpdatePinnedStackBoundsListener);
-        mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mMenuController.hideMenu();
+        if (isMenuVisible != mIsMenuVisible) {
+            if (isMenuVisible) {
+                // Save the current snap fraction and if we do not drag or move the PiP, then
+                // we store back to this snap fraction.  Otherwise, we'll reset the snap
+                // fraction and snap to the closest edge
+                Rect expandedBounds = new Rect(mExpandedBounds);
+                mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
+                        mMovementBounds, mExpandedMovementBounds);
+            } else {
+                // Try and restore the PiP to the closest edge, using the saved snap fraction
+                // if possible
+                Rect normalBounds = new Rect(mNormalBounds);
+                mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
+                        mNormalMovementBounds);
             }
-        });
-        mPinnedStackBoundsAnimator.start();
-    }
-
-    /**
-     * Flings the PIP to the closest snap target.
-     */
-    private Rect flingToSnapTarget(float velocity, float velocityX, float velocityY) {
-        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
-                mPinnedStackBounds, velocityX, velocityY);
-        if (!mPinnedStackBounds.equals(toBounds)) {
-            mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
-                toBounds, 0, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
-            mFlingAnimationUtils.apply(mPinnedStackBoundsAnimator, 0,
-                distanceBetweenRectOffsets(mPinnedStackBounds, toBounds),
-                velocity);
-            mPinnedStackBoundsAnimator.start();
-        }
-        return toBounds;
-    }
-
-    /**
-     * Animates the PIP to the closest snap target.
-     */
-    private Rect animateToClosestSnapTarget() {
-        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
-                mPinnedStackBounds);
-        if (!mPinnedStackBounds.equals(toBounds)) {
-            mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
-                toBounds, SNAP_STACK_DURATION, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
-            mPinnedStackBoundsAnimator.start();
-        }
-        return toBounds;
-    }
-
-    /**
-     * Animates the dismissal of the PIP over the dismiss target bounds.
-     */
-    private void animateDismissPinnedStack(Rect dismissBounds) {
-        Rect toBounds = new Rect(dismissBounds.centerX(),
-            dismissBounds.centerY(),
-            dismissBounds.centerX() + 1,
-            dismissBounds.centerY() + 1);
-        mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
-            toBounds, DISMISS_STACK_DURATION, FAST_OUT_LINEAR_IN, mUpdatePinnedStackBoundsListener);
-        mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
-            }
-        });
-        mPinnedStackBoundsAnimator.start();
-    }
-
-    /**
-     * Resizes the pinned stack back to fullscreen.
-     */
-    void expandPinnedStackToFullscreen() {
-        BackgroundThread.getHandler().post(() -> {
-            try {
-                mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */,
-                        true /* allowResizeInDockedMode */, true /* preserveWindows */,
-                        true /* animate */, EXPAND_STACK_DURATION);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error showing PIP menu activity", e);
-            }
-        });
-    }
-
-    /**
-     * Tries to the move the pinned stack to the given {@param bounds}.
-     */
-    private void movePinnedStack(Rect bounds) {
-        if (!bounds.equals(mPinnedStackBounds)) {
-            mPinnedStackBounds.set(bounds);
-            if (mEnableDragToDismiss) {
-                mDismissViewController.updateDismissTarget(bounds);
-            }
-            mMotionHelper.resizeToBounds(mPinnedStackBounds);
+            mIsMenuVisible = isMenuVisible;
+            updateMovementBounds();
         }
     }
 
     /**
-     * Dismisses the pinned stack.
+     * @return the motion helper.
      */
-    private void dismissPinnedStack() {
-        try {
-            mActivityManager.removeStack(PINNED_STACK_ID);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to remove PIP", e);
-        }
-    }
-
-    /**
-     * Updates the movement bounds of the pinned stack.
-     */
-    private void updateBoundedPinnedStackBounds(boolean updatePinnedStackBounds) {
-        try {
-            StackInfo info = mActivityManager.getStackInfo(PINNED_STACK_ID);
-            if (info != null) {
-                if (updatePinnedStackBounds) {
-                    mPinnedStackBounds.set(info.bounds);
-                }
-                mWindowManager.getStableInsets(info.displayId, mStableInsets);
-                mBoundedPinnedStackBounds.set(mWindowManager.getPictureInPictureMovementBounds(
-                        info.displayId));
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Could not fetch PIP movement bounds.", e);
-        }
-    }
-
-    /**
-     * @return the distance between points {@param p1} and {@param p2}.
-     */
-    private float distanceBetweenRectOffsets(Rect r1, Rect r2) {
-        return PointF.length(r1.left - r2.left, r1.top - r2.top);
+    public PipMotionHelper getMotionHelper() {
+        return mMotionHelper;
     }
 
     /**
@@ -593,25 +445,31 @@
 
         @Override
         boolean onMove(PipTouchState touchState) {
+            if (touchState.startedDragging()) {
+                mSavedSnapFraction = -1f;
+            }
+
             if (touchState.startedDragging() && mEnableDragToDismiss) {
                 mHandler.removeCallbacks(mShowDismissAffordance);
-                mDismissViewController.showDismissTarget(mPinnedStackBounds);
+                mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
             }
 
             if (touchState.isDragging()) {
                 // Move the pinned stack freely
-                PointF lastDelta = touchState.getLastTouchDelta();
-                float left = mPinnedStackBounds.left + lastDelta.x;
-                float top = mPinnedStackBounds.top + lastDelta.y;
+                mTmpBounds.set(mMotionHelper.getBounds());
+                final PointF lastDelta = touchState.getLastTouchDelta();
+                float left = mTmpBounds.left + lastDelta.x;
+                float top = mTmpBounds.top + lastDelta.y;
                 if (!touchState.allowDraggingOffscreen()) {
-                    left = Math.max(mBoundedPinnedStackBounds.left, Math.min(
-                            mBoundedPinnedStackBounds.right, left));
+                    left = Math.max(mMovementBounds.left, Math.min(mMovementBounds.right, left));
                 }
-                top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
-                        mBoundedPinnedStackBounds.bottom, top));
-                mTmpBounds.set(mPinnedStackBounds);
+                top = Math.max(mMovementBounds.top, Math.min(mMovementBounds.bottom, top));
                 mTmpBounds.offsetTo((int) left, (int) top);
-                movePinnedStack(mTmpBounds);
+                mMotionHelper.movePip(mTmpBounds);
+
+                if (mEnableDragToDismiss) {
+                    mDismissViewController.updateDismissTarget(mTmpBounds);
+                }
                 return true;
             }
             return false;
@@ -626,9 +484,12 @@
                     final float velocity = PointF.length(vel.x, vel.y);
                     if (touchState.isDragging()
                             && velocity < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-                        if (mDismissViewController.shouldDismiss(mPinnedStackBounds)) {
+                        if (mDismissViewController.shouldDismiss(mMotionHelper.getBounds())) {
                             Rect dismissBounds = mDismissViewController.getDismissBounds();
-                            animateDismissPinnedStack(dismissBounds);
+                            mMotionHelper.animateDismissFromDrag(dismissBounds);
+                            MetricsLogger.action(mContext,
+                                    MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
+                                    METRIC_VALUE_DISMISSED_BY_DRAG);
                             return true;
                         }
                     }
@@ -638,34 +499,34 @@
             }
             if (touchState.isDragging()) {
                 PointF vel = mTouchState.getVelocity();
-                if (!mIsMinimized && (shouldMinimizedPinnedStack()
+                if (!mIsMinimized && (mMotionHelper.shouldMinimizePip()
                         || isHorizontalFlingTowardsCurrentEdge(vel))) {
                     // Pip should be minimized
-                    setMinimizedState(true);
-                    animateToClosestMinimizedTarget();
+                    setMinimizedStateInternal(true);
+                    mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController);
                     return true;
                 }
                 if (mIsMinimized) {
                     // If we're dragging and it wasn't a minimize gesture
                     // then we shouldn't be minimized.
-                    setMinimizedState(false);
+                    setMinimizedStateInternal(false);
                 }
 
                 final float velocity = PointF.length(vel.x, vel.y);
                 if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-                    flingToSnapTarget(velocity, vel.x, vel.y);
+                    mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds);
                 } else {
-                    animateToClosestSnapTarget();
+                    mMotionHelper.animateToClosestSnapTarget(mMovementBounds);
                 }
             } else if (mIsMinimized) {
                 // This was a tap, so no longer minimized
-                animateToClosestSnapTarget();
-                setMinimizedState(false);
+                mMotionHelper.animateToClosestSnapTarget(mMovementBounds);
+                setMinimizedStateInternal(false);
             } else if (!mIsTappingThrough) {
                 mMenuController.showMenu();
                 mIsTappingThrough = true;
             } else {
-                expandPinnedStackToFullscreen();
+                mMotionHelper.expandPip();
             }
             return true;
         }
@@ -679,17 +540,30 @@
         final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
         final boolean isFling = PointF.length(vel.x, vel.y) > mFlingAnimationUtils
                 .getMinVelocityPxPerSecond();
-        final boolean towardsCurrentEdge = onEdge(true /* left */) && vel.x < 0
-                || onEdge(false /* right */) && vel.x > 0;
+        final boolean towardsCurrentEdge = isOverEdge(true /* left */) && vel.x < 0
+                || isOverEdge(false /* right */) && vel.x > 0;
         return towardsCurrentEdge && isHorizontal && isFling;
     }
 
-    private boolean onEdge(boolean checkLeft) {
+    /**
+     * @return whether the given bounds are on the left or right edge (depending on
+     *         {@param checkLeft})
+     */
+    private boolean isOverEdge(boolean checkLeft) {
+        final Rect bounds = mMotionHelper.getBounds();
         if (checkLeft) {
-            return mPinnedStackBounds.left <= mBoundedPinnedStackBounds.left;
+            return bounds.left <= mMovementBounds.left;
         } else {
-            return mPinnedStackBounds.right >= mBoundedPinnedStackBounds.right
-                    + mPinnedStackBounds.width();
+            return bounds.right >= mMovementBounds.right + bounds.width();
         }
     }
+
+    /**
+     * Updates the current movement bounds based on whether the menu is currently visible.
+     */
+    private void updateMovementBounds() {
+        mMovementBounds = mIsMenuVisible
+                ? mExpandedMovementBounds
+                : mNormalMovementBounds;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
index 2e84ced..868b34b7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -34,6 +34,7 @@
     private final PointF mLastTouch = new PointF();
     private final PointF mLastDelta = new PointF();
     private final PointF mVelocity = new PointF();
+    private boolean mIsUserInteracting = false;
     private boolean mIsDragging = false;
     private boolean mStartedDragging = false;
     private boolean mAllowDraggingOffscreen = false;
@@ -57,6 +58,7 @@
                 mIsDragging = false;
                 mStartedDragging = false;
                 mAllowDraggingOffscreen = true;
+                mIsUserInteracting = true;
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -107,6 +109,7 @@
                 // Fall through to clean up
             }
             case MotionEvent.ACTION_CANCEL: {
+                mIsUserInteracting = false;
                 recycleVelocityTracker();
                 break;
             }
@@ -151,6 +154,13 @@
     }
 
     /**
+     * @return whether the user is currently interacting with the PiP.
+     */
+    public boolean isUserInteracting() {
+        return mIsUserInteracting;
+    }
+
+    /**
      * @return whether the user has started dragging just in the last handled touch event.
      */
     public boolean startedDragging() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 964fefa..e3db16a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.media.session.MediaController;
@@ -39,6 +40,8 @@
 import android.util.Log;
 import android.util.Pair;
 import android.view.Display;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
 
@@ -51,6 +54,8 @@
 import java.util.List;
 
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.android.systemui.Prefs.Key.TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN;
 
 /**
@@ -146,7 +151,7 @@
     private List<MediaListener> mMediaListeners = new ArrayList<>();
     private Rect mCurrentPipBounds;
     private Rect mPipBounds;
-    private Rect mDefaultPipBounds;
+    private Rect mDefaultPipBounds = new Rect();
     private Rect mSettingsPipBounds;
     private Rect mMenuModePipBounds;
     private Rect mRecentsPipBounds;
@@ -159,6 +164,8 @@
     private boolean mOnboardingShown;
     private String[] mLastPackagesResourceGranted;
 
+    private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
+
     private final Runnable mResizePinnedStackRunnable = new Runnable() {
         @Override
         public void run() {
@@ -196,6 +203,32 @@
                 }
             };
 
+    /**
+     * Handler for messages from the PIP controller.
+     */
+    private class PinnedStackListener extends IPinnedStackListener.Stub {
+
+        @Override
+        public void onListenerRegistered(IPinnedStackController controller) {}
+
+        @Override
+        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
+
+        @Override
+        public void onMinimizedStateChanged(boolean isMinimized) {}
+
+        @Override
+        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+                boolean fromImeAdjustement) {
+            mHandler.post(() -> {
+                mDefaultPipBounds.set(normalBounds);
+            });
+        }
+
+        @Override
+        public void onActionsChanged(ParceledListSlice actions) {}
+    }
+
     private PipManager() { }
 
     /**
@@ -221,16 +254,16 @@
         mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
         mMediaSessionManager =
                 (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
+
+        try {
+            mWindowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register pinned stack listener", e);
+        }
     }
 
     private void loadConfigurationsAndApply() {
         Resources res = mContext.getResources();
-        try {
-            mDefaultPipBounds = mWindowManager.getPictureInPictureDefaultBounds(
-                    Display.DEFAULT_DISPLAY);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get default PIP bounds", e);
-        }
         mSettingsPipBounds = Rect.unflattenFromString(res.getString(
                 R.string.pip_settings_bounds));
         mMenuModePipBounds = Rect.unflattenFromString(res.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 3d36868..471c3ae 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -34,6 +34,7 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Slog;
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -45,6 +46,8 @@
     static final String TAG = "PowerUI";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS;
+    private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS;
+    private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer
 
     private final Handler mHandler = new Handler();
     private final Receiver mReceiver = new Receiver();
@@ -62,7 +65,10 @@
 
     private long mScreenOffTime = -1;
 
-    private float mThrottlingTemp;
+    private float mThresholdTemp;
+    private float[] mRecentTemps = new float[MAX_RECENT_TEMPS];
+    private int mNumTemps;
+    private long mNextLogTime;
 
     public void start() {
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -229,10 +235,10 @@
             return;
         }
 
-        mThrottlingTemp = Settings.Global.getFloat(resolver, Settings.Global.WARNING_TEMPERATURE,
+        mThresholdTemp = Settings.Global.getFloat(resolver, Settings.Global.WARNING_TEMPERATURE,
                 resources.getInteger(R.integer.config_warningTemperature));
 
-        if (mThrottlingTemp < 0f) {
+        if (mThresholdTemp < 0f) {
             // Get the throttling temperature. No need to check if we're not throttling.
             float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
                     HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
@@ -242,41 +248,86 @@
                     || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
                 return;
             }
-            mThrottlingTemp = throttlingTemps[0];
+            mThresholdTemp = throttlingTemps[0];
         }
+        setNextLogTime();
 
         // We have passed all of the checks, start checking the temp
         updateTemperatureWarning();
     }
 
     private void updateTemperatureWarning() {
-        StatusBar statusBar = getComponent(StatusBar.class);
-        if (statusBar != null && statusBar.isDeviceInVrMode()) {
-            // ensure the warning isn't showing, since VR shows its own warning
-            mWarnings.dismissTemperatureWarning();
-        } else {
-            float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
-                    HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
-                    HardwarePropertiesManager.TEMPERATURE_CURRENT);
-            boolean shouldShowTempWarning = false;
-            for (float temp : temps) {
-                if (temp >= mThrottlingTemp) {
-                    Slog.i(TAG, "currentTemp=" + temp + ", throttlingTemp=" + mThrottlingTemp);
-                    shouldShowTempWarning = true;
-                    break;
-                }
-            }
-            if (shouldShowTempWarning) {
+        float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                HardwarePropertiesManager.TEMPERATURE_CURRENT);
+        if (temps.length != 0) {
+            float temp = temps[0];
+            mRecentTemps[mNumTemps++] = temp;
+
+            StatusBar statusBar = getComponent(StatusBar.class);
+            if (statusBar != null && !statusBar.isDeviceInVrMode()
+                    && temp >= mThresholdTemp) {
+                logAtTemperatureThreshold(temp);
                 mWarnings.showTemperatureWarning();
             } else {
                 mWarnings.dismissTemperatureWarning();
             }
         }
 
-        // TODO: skip this when in VR mode since we already get a callback
+        logTemperatureStats();
+
         mHandler.postDelayed(this::updateTemperatureWarning, TEMPERATURE_INTERVAL);
     }
 
+    private void logAtTemperatureThreshold(float temp) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("currentTemp=").append(temp)
+                .append(",thresholdTemp=").append(mThresholdTemp)
+                .append(",batteryStatus=").append(mBatteryStatus)
+                .append(",recentTemps=");
+        for (int i = 0; i < mNumTemps; i++) {
+            sb.append(mRecentTemps[i]).append(',');
+        }
+        Slog.i(TAG, sb.toString());
+    }
+
+    /**
+     * Calculates and logs min, max, and average
+     * {@link HardwarePropertiesManager#DEVICE_TEMPERATURE_SKIN} over the past
+     * {@link #TEMPERATURE_LOGGING_INTERVAL}.
+     */
+    private void logTemperatureStats() {
+        if (mNextLogTime > System.currentTimeMillis() && mNumTemps != MAX_RECENT_TEMPS) {
+            return;
+        }
+
+        if (mNumTemps > 0) {
+            float sum = mRecentTemps[0], min = mRecentTemps[0], max = mRecentTemps[0];
+            for (int i = 1; i < mNumTemps; i++) {
+                float temp = mRecentTemps[i];
+                sum += temp;
+                if (temp > max) {
+                    max = temp;
+                }
+                if (temp < min) {
+                    min = temp;
+                }
+            }
+
+            float avg = sum / mNumTemps;
+            Slog.i(TAG, "avg=" + avg + ",min=" + min + ",max=" + max);
+            MetricsLogger.histogram(mContext, "device_skin_temp_avg", (int) avg);
+            MetricsLogger.histogram(mContext, "device_skin_temp_min", (int) min);
+            MetricsLogger.histogram(mContext, "device_skin_temp_max", (int) max);
+        }
+        setNextLogTime();
+        mNumTemps = 0;
+    }
+
+    private void setNextLogTime() {
+        mNextLogTime = System.currentTimeMillis() + TEMPERATURE_LOGGING_INTERVAL;
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mLowBatteryAlertCloseLevel=");
         pw.println(mLowBatteryAlertCloseLevel);
@@ -303,8 +354,10 @@
                 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
         pw.print("bucket: ");
         pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
-        pw.print("mThrottlingTemp=");
-        pw.println(Float.toString(mThrottlingTemp));
+        pw.print("mThresholdTemp=");
+        pw.println(Float.toString(mThresholdTemp));
+        pw.print("mNextLogTime=");
+        pw.println(Long.toString(mNextLogTime));
         mWarnings.dump(pw);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index a5a1eaa..3b9e7bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -99,8 +99,9 @@
             record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
             previousView = record.tileView.updateAccessibilityOrder(previousView);
         }
-        setMeasuredDimension(width,
-                (mCellHeight + mCellMargin) * rows + (mCellMarginTop - mCellMargin));
+        int height = (mCellHeight + mCellMargin) * rows + (mCellMarginTop - mCellMargin);
+        if (height < 0) height = 0;
+        setMeasuredDimension(width, height);
     }
 
     private static int exactly(int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 3afbc35..dea56aa1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -237,6 +237,8 @@
         i.setPackage(mComponent.getPackageName());
         i = resolveIntent(i);
         if (i != null) {
+            i.putExtra(TileService.EXTRA_COMPONENT, mComponent);
+            i.putExtra(TileService.EXTRA_STATE, mTile.getState());
             return i;
         }
         return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 6f1f977..fff8305 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -197,7 +197,7 @@
             }
             mDrawable.onBatteryLevelChanged(100, false, false);
             mDrawable.onPowerSaveChanged(true);
-            mDrawable.disableShowPercent();
+            mDrawable.setShowPercent(false);
             ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
             Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
             checkbox.setChecked(mPowerSave);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index a4cd14d..b48b829 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -179,7 +179,7 @@
         }
 
         @Override
-        public void onKeyguardChanged() {
+        public void onKeyguardShowingChanged() {
             refreshState();
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 70f8109..dab5967 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.UserManager;
@@ -37,6 +40,9 @@
 
 /** Quick settings tile: Hotspot **/
 public class HotspotTile extends QSTile<QSTile.AirplaneBooleanState> {
+    static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
+             "com.android.settings", "com.android.settings.TetherSettings"));
+
     private final AnimationIcon mEnable =
             new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
                     R.drawable.ic_hotspot_disable);
@@ -94,7 +100,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+        return new Intent(TETHER_SETTINGS);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 5374f18..423a1df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -141,7 +141,7 @@
         }
 
         @Override
-        public void onKeyguardChanged() {
+        public void onKeyguardShowingChanged() {
             refreshState();
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 9157e33..e635162 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -205,7 +205,6 @@
         sTaskLoader = new RecentsTaskLoader(mContext);
         sConfiguration = new RecentsConfiguration(mContext);
         mHandler = new Handler();
-        getComponent(CommandQueue.class).addCallbacks(this);
         UiModeManager uiModeManager = (UiModeManager) mContext.
                 getSystemService(Context.UI_MODE_SERVICE);
         if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
@@ -234,6 +233,7 @@
         if (sSystemServicesProxy.isSystemUser(processUser)) {
             // For the system user, initialize an instance of the interface that we can pass to the
             // secondary user
+            getComponent(CommandQueue.class).addCallbacks(this);
             mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
         } else {
             // For the secondary user, bind to the primary user's service to get a persistent
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 609e3fb..55491b2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -76,6 +76,7 @@
 import com.android.systemui.recents.views.TaskStackViewScroller;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
+import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 import com.android.systemui.stackdivider.DividerView;
 import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -637,13 +638,28 @@
             stackLayout.initialize(displayRect, windowRect, mTaskStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
             mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
+            // Get the width of a task view so that we know how wide to draw the header bar.
+            int taskViewWidth = 0;
+            if (mDummyStackView.useGridLayout()) {
+                TaskGridLayoutAlgorithm gridLayout = mDummyStackView.getGridAlgorithm();
+                gridLayout.initialize(windowRect);
+                taskViewWidth = (int) gridLayout.getTransform(0 /* taskIndex */,
+                        stack.getTaskCount(), new TaskViewTransform(), stackLayout).rect.width();
+            } else {
+                Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
+                if (!taskViewBounds.isEmpty()) {
+                    taskViewWidth = taskViewBounds.width();
+                }
+            }
 
-            Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
-            if (!taskViewBounds.isEmpty()) {
-                int taskViewWidth = taskViewBounds.width();
+            if (taskViewWidth > 0) {
                 synchronized (mHeaderBarLock) {
                     if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
                             mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
+                        if (mDummyStackView.useGridLayout()) {
+                            mHeaderBar.setShouldDarkenBackgroundColor(true);
+                            mHeaderBar.setNoUserInteractionState();
+                        }
                         mHeaderBar.forceLayout();
                         mHeaderBar.measure(
                                 MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index fb94c7e..0160eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -96,6 +96,7 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import com.android.systemui.recents.views.grid.GridTaskView;
+import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -447,6 +448,11 @@
         return mLayoutAlgorithm;
     }
 
+    /** Returns the grid algorithm for this task stack. */
+    public TaskGridLayoutAlgorithm getGridAlgorithm() {
+        return mLayoutAlgorithm.mTaskGridLayoutAlgorithm;
+    }
+
     /**
      * Returns the touch handler for this task stack.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 45e766c..9a52a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -151,7 +151,7 @@
     @ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
     protected TaskViewThumbnail mThumbnailView;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
-    TaskViewHeader mHeaderView;
+    protected TaskViewHeader mHeaderView;
     private View mActionButtonView;
     private View mIncompatibleAppToastView;
     private TaskViewCallbacks mCb;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 0777163..dc666e9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -91,6 +91,9 @@
             if (mColor != color || Float.compare(mDimAlpha, dimAlpha) != 0) {
                 mColor = color;
                 mDimAlpha = dimAlpha;
+                if (mShouldDarkenBackgroundColor) {
+                    color = getSecondaryColor(color, false /* useLightOverlayColor */);
+                }
                 mBackgroundPaint.setColor(color);
 
                 ColorUtils.colorToHSL(color, mTmpHSL);
@@ -179,6 +182,10 @@
     // Header dim, which is only used when task view hardware layers are not used
     private Paint mDimLayerPaint = new Paint();
 
+    // Whether the background color should be darkened to differentiate from the primary color.
+    // Used in grid layout.
+    private boolean mShouldDarkenBackgroundColor = false;
+
     private CountDownTimer mFocusTimerCountDown;
 
     public TaskViewHeader(Context context) {
@@ -443,6 +450,13 @@
     }
 
     /**
+     * Sets whether the background color should be darkened to differentiate from the primary color.
+     */
+    public void setShouldDarkenBackgroundColor(boolean flag) {
+        mShouldDarkenBackgroundColor = flag;
+    }
+
+    /**
      * Binds the bar view to the task.
      */
     public void bindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
@@ -557,7 +571,7 @@
      * Mark this task view that the user does has not interacted with the stack after a certain
      * time.
      */
-    void setNoUserInteractionState() {
+    public void setNoUserInteractionState() {
         mDismissButton.setVisibility(View.VISIBLE);
         mDismissButton.animate().cancel();
         mDismissButton.setAlpha(1f);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
index a86abf6..8b4700c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
@@ -53,6 +53,7 @@
         mThumbnailView.setOverlayHeaderOnThumbnailActionBar(false);
         mThumbnailView.updateThumbnailMatrix();
         mThumbnailView.setTranslationY(mHeaderHeight);
+        mHeaderView.setShouldDarkenBackgroundColor(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 7825e9e..d3f997a 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -295,8 +295,10 @@
 
         mAutomaticAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_automatic_brightness_available);
-        mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
-        mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
+        mPower = IPowerManager.Stub.asInterface(ServiceManager.getService(
+                Context.POWER_SERVICE));
+        mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
+                Context.VR_SERVICE));
     }
 
     public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index b9a0f74..0b09acc 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -72,6 +72,10 @@
         return mMinimized;
     }
 
+    public boolean isHomeStackResizable() {
+        return mHomeStackResizable;
+    }
+
     private void addDivider(Configuration configuration) {
         mView = (DividerView)
                 LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
@@ -119,6 +123,7 @@
         mView.post(new Runnable() {
             @Override
             public void run() {
+                mHomeStackResizable = isHomeStackResizable;
                 if (mMinimized != minimized) {
                     mMinimized = minimized;
                     updateTouchable();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 49035ba..6f59fe2 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1241,7 +1241,8 @@
 
     public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
         int dockSide = mWindowManagerProxy.getDockSide();
-        if (dockSide != WindowManager.DOCKED_INVALID && !mDockedStackMinimized) {
+        if (dockSide != WindowManager.DOCKED_INVALID && (mHomeStackResizable
+                || !mDockedStackMinimized)) {
             startDragging(false /* animate */, false /* touching */);
             SnapTarget target = dockSideTopLeft(dockSide)
                     ? mSnapAlgorithm.getDismissEndTarget()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 4b1baa2..0bd6491 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -105,7 +105,7 @@
     private boolean mDimmed;
     private boolean mDark;
 
-    private int mBgTint = NO_COLOR;
+    protected int mBgTint = NO_COLOR;
     private float mBgAlpha = 1f;
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 477701c..5366da1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -25,7 +25,6 @@
 import android.os.Message;
 import android.support.annotation.VisibleForTesting;
 import android.util.Pair;
-import android.view.KeyEvent;
 
 import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBar;
@@ -63,9 +62,6 @@
     private static final int MSG_SET_WINDOW_STATE              = 12 << MSG_SHIFT;
     private static final int MSG_SHOW_RECENT_APPS              = 13 << MSG_SHIFT;
     private static final int MSG_HIDE_RECENT_APPS              = 14 << MSG_SHIFT;
-    private static final int MSG_BUZZ_BEEP_BLINKED             = 15 << MSG_SHIFT;
-    private static final int MSG_NOTIFICATION_LIGHT_OFF        = 16 << MSG_SHIFT;
-    private static final int MSG_NOTIFICATION_LIGHT_PULSE      = 17 << MSG_SHIFT;
     private static final int MSG_SHOW_SCREEN_PIN_REQUEST       = 18 << MSG_SHIFT;
     private static final int MSG_APP_TRANSITION_PENDING        = 19 << MSG_SHIFT;
     private static final int MSG_APP_TRANSITION_CANCELLED      = 20 << MSG_SHIFT;
@@ -95,6 +91,8 @@
     private final Object mLock = new Object();
     private ArrayList<Callbacks> mCallbacks = new ArrayList<>();
     private Handler mHandler = new H(Looper.getMainLooper());
+    private int mDisable1;
+    private int mDisable2;
 
     /**
      * These methods are called back on the main thread.
@@ -121,13 +119,10 @@
         default void toggleKeyboardShortcutsMenu(int deviceId) { }
         default void cancelPreloadRecentApps() { }
         default void setWindowState(int window, int state) { }
-        default void buzzBeepBlinked() { }
-        default void notificationLightOff() { }
-        default void notificationLightPulse(int argb, int onMillis, int offMillis) { }
         default void showScreenPinningRequest(int taskId) { }
-        default void appTransitionPending() { }
+        default void appTransitionPending(boolean forced) { }
         default void appTransitionCancelled() { }
-        default void appTransitionStarting(long startTime, long duration) { }
+        default void appTransitionStarting(long startTime, long duration, boolean forced) { }
         default void appTransitionFinished() { }
         default void showAssistDisclosure() { }
         default void startAssist(Bundle args) { }
@@ -147,6 +142,7 @@
 
     public void addCallbacks(Callbacks callbacks) {
         mCallbacks.add(callbacks);
+        callbacks.disable(mDisable1, mDisable2, false /* animate */);
     }
 
     public void removeCallbacks(Callbacks callbacks) {
@@ -170,6 +166,8 @@
 
     public void disable(int state1, int state2) {
         synchronized (mLock) {
+            mDisable1 = state1;
+            mDisable2 = state2;
             mHandler.removeMessages(MSG_DISABLE);
             mHandler.obtainMessage(MSG_DISABLE, state1, state2, null).sendToTarget();
         }
@@ -313,26 +311,6 @@
         }
     }
 
-    public void buzzBeepBlinked() {
-        synchronized (mLock) {
-            mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED);
-            mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED);
-        }
-    }
-
-    public void notificationLightOff() {
-        synchronized (mLock) {
-            mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF);
-        }
-    }
-
-    public void notificationLightPulse(int argb, int onMillis, int offMillis) {
-        synchronized (mLock) {
-            mHandler.obtainMessage(MSG_NOTIFICATION_LIGHT_PULSE, onMillis, offMillis, argb)
-                    .sendToTarget();
-        }
-    }
-
     public void showScreenPinningRequest(int taskId) {
         synchronized (mLock) {
             mHandler.obtainMessage(MSG_SHOW_SCREEN_PIN_REQUEST, taskId, 0, null)
@@ -341,9 +319,13 @@
     }
 
     public void appTransitionPending() {
+        appTransitionPending(false /* forced */);
+    }
+
+    public void appTransitionPending(boolean forced) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
-            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+            mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, forced ? 1 : 0, 0).sendToTarget();
         }
     }
 
@@ -355,10 +337,14 @@
     }
 
     public void appTransitionStarting(long startTime, long duration) {
+        appTransitionStarting(startTime, duration, false /* forced */);
+    }
+
+    public void appTransitionStarting(long startTime, long duration, boolean forced) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
-            mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration))
-                    .sendToTarget();
+            mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, forced ? 1 : 0, 0,
+                    Pair.create(startTime, duration)).sendToTarget();
         }
     }
 
@@ -524,21 +510,6 @@
                         mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2);
                     }
                     break;
-                case MSG_BUZZ_BEEP_BLINKED:
-                    for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).buzzBeepBlinked();
-                    }
-                    break;
-                case MSG_NOTIFICATION_LIGHT_OFF:
-                    for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).notificationLightOff();
-                    }
-                    break;
-                case MSG_NOTIFICATION_LIGHT_PULSE:
-                    for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
-                    }
-                    break;
                 case MSG_SHOW_SCREEN_PIN_REQUEST:
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).showScreenPinningRequest(msg.arg1);
@@ -546,7 +517,7 @@
                     break;
                 case MSG_APP_TRANSITION_PENDING:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).appTransitionPending();
+                        mCallbacks.get(i).appTransitionPending(msg.arg1 != 0);
                     }
                     break;
                 case MSG_APP_TRANSITION_CANCELLED:
@@ -557,7 +528,8 @@
                 case MSG_APP_TRANSITION_STARTING:
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
-                        mCallbacks.get(i).appTransitionStarting(data.first, data.second);
+                        mCallbacks.get(i).appTransitionStarting(data.first, data.second,
+                                msg.arg1 != 0);
                     }
                     break;
                 case MSG_APP_TRANSITION_FINISHED:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 85e2bd6..2e9c7fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1880,14 +1880,14 @@
             } else if (isUserLocked()) {
                 return mChildrenContainer.getGroupExpandFraction();
             }
-        } else if (isColorized()) {
+        } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
             return -1.0f;
         }
         return 0.0f;
     }
 
     private boolean isColorized() {
-        return mIsColorized;
+        return mIsColorized && mBgTint != NO_COLOR;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index e8e9d4e..2425076 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -68,6 +68,7 @@
     private float mMaxShelfEnd;
     private int mRelativeOffset;
     private boolean mInteractive;
+    private boolean mAnimationsEnabled = true;
 
     public NotificationShelf(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -388,12 +389,13 @@
 
         View rowIcon = row.getNotificationIcon();
         float notificationIconPosition = row.getTranslationY() + row.getContentTranslation();
-        if (usingLinearInterpolation) {
+        boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf();
+        if (usingLinearInterpolation && !stayingInShelf) {
             // If we interpolate from the notification position, this might lead to a slightly
             // odd interpolation, since the notification position changes as well. Let's interpolate
             // from a fixed distance. We can only do this if we don't animate and the icon is
             // always in the interpolated positon.
-            notificationIconPosition = mMaxShelfEnd - getIntrinsicHeight() - iconTransformDistance;
+            notificationIconPosition = getTranslationY() - iconTransformDistance;
         }
         float notificationIconSize = 0.0f;
         int iconTopPadding;
@@ -426,7 +428,7 @@
             iconState.hidden = transitionAmount == 0.0f;
             iconState.alpha = alpha;
             iconState.yTranslation = iconYTranslation;
-            if (row.isInShelf() && !row.isTransformingIntoShelf()) {
+            if (stayingInShelf) {
                 iconState.iconAppearAmount = 1.0f;
                 iconState.alpha = 1.0f;
                 iconState.scaleX = 1.0f;
@@ -573,6 +575,15 @@
         mMaxShelfEnd = maxShelfEnd;
     }
 
+    public void setAnimationsEnabled(boolean enabled) {
+        mAnimationsEnabled = enabled;
+        mCollapsedIcons.setAnimationsEnabled(enabled);
+        if (!enabled) {
+            // we need to wait with enabling the animations until the first frame has passed
+            mShelfIcons.setAnimationsEnabled(false);
+        }
+    }
+
     private class ShelfState extends ExpandableViewState {
         private float openedAmount;
         private boolean hasItemsInStableShelf;
@@ -585,6 +596,7 @@
             setOpenedAmount(openedAmount);
             updateAppearance();
             setHasItemsInStableShelf(hasItemsInStableShelf);
+            mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
         }
 
         @Override
@@ -594,6 +606,7 @@
             setOpenedAmount(openedAmount);
             updateAppearance();
             setHasItemsInStableShelf(hasItemsInStableShelf);
+            mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 66cc15d..7f28c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import com.android.internal.util.Preconditions;
+import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -39,8 +40,8 @@
     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
     private final HeadsUpManager mHeadsUpManager;
 
-    public RemoteInputController(StatusBarWindowManager sbwm, HeadsUpManager headsUpManager) {
-        addCallback(sbwm);
+    public RemoteInputController(HeadsUpManager headsUpManager) {
+        addCallback(Dependency.get(StatusBarWindowManager.class));
         mHeadsUpManager = headsUpManager;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 45eb5df..89041f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -43,6 +43,8 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
@@ -54,10 +56,9 @@
 import java.util.List;
 
 // Intimately tied to the design of res/layout/signal_cluster_view.xml
-public class SignalClusterView
-        extends LinearLayout
-        implements NetworkControllerImpl.SignalCallback,
-        SecurityController.SecurityControllerCallback, Tunable {
+public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
+        SecurityController.SecurityControllerCallback, Tunable,
+        DarkReceiver {
 
     static final String TAG = "SignalClusterView";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -581,7 +582,8 @@
         return colorAccent;
     }
 
-    public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+    @Override
+    public void onDarkChanged(Rect tintArea, float darkIntensity, int tint) {
         boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
                 || !mTintArea.equals(tintArea);
         mIconTint = tint;
@@ -593,16 +595,16 @@
     }
 
     private void applyIconTint() {
-        setTint(mVpn, StatusBarIconController.getTint(mTintArea, mVpn, mIconTint));
-        setTint(mAirplane, StatusBarIconController.getTint(mTintArea, mAirplane, mIconTint));
+        setTint(mVpn, DarkIconDispatcher.getTint(mTintArea, mVpn, mIconTint));
+        setTint(mAirplane, DarkIconDispatcher.getTint(mTintArea, mAirplane, mIconTint));
         applyDarkIntensity(
-                StatusBarIconController.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
+                DarkIconDispatcher.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
                 mNoSims, mNoSimsDark);
         applyDarkIntensity(
-                StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
+                DarkIconDispatcher.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
                 mWifi, mWifiDark);
         applyDarkIntensity(
-                StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
+                DarkIconDispatcher.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
                 mEthernet, mEthernetDark);
         for (int i = 0; i < mPhoneStates.size(); i++) {
             mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea);
@@ -740,10 +742,10 @@
 
         public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
             applyDarkIntensity(
-                    StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
+                    DarkIconDispatcher.getDarkIntensity(tintArea, mMobile, darkIntensity),
                     mMobile, mMobileDark);
-            setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
-            setTint(mMobileRoaming, StatusBarIconController.getTint(tintArea, mMobileRoaming,
+            setTint(mMobileType, DarkIconDispatcher.getTint(tintArea, mMobileType, tint));
+            setTint(mMobileRoaming, DarkIconDispatcher.getTint(tintArea, mMobileRoaming,
                     tint));
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 399b0d2..6283148 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -256,9 +256,16 @@
         if (mIcon == null) {
             return false;
         }
-        Drawable drawable = getIcon(mIcon);
+        Drawable drawable;
+        try {
+            drawable = getIcon(mIcon);
+        } catch (OutOfMemoryError e) {
+            Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
+            return false;
+        }
+
         if (drawable == null) {
-            Log.w(TAG, "No icon for slot " + mSlot);
+            Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
             return false;
         }
         if (withClear) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 4161389..f53dad5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -32,17 +32,19 @@
 import android.view.ViewStub;
 import android.view.WindowManager;
 import android.widget.LinearLayout;
+
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
+import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.NavigationBarView;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
@@ -75,7 +77,6 @@
 
         createBatteryController();
         mCarBatteryController.startListening();
-        mConnectedDeviceSignalController.startListening();
     }
 
     @Override
@@ -87,32 +88,40 @@
     }
 
     @Override
-    protected PhoneStatusBarView makeStatusBarView() {
-        PhoneStatusBarView statusBarView = super.makeStatusBarView();
+    protected void makeStatusBarView() {
+        super.makeStatusBarView();
 
-        mBatteryMeterView = ((BatteryMeterView) statusBarView.findViewById(R.id.battery));
+        FragmentHostManager manager = FragmentHostManager.get(mStatusBarWindow);
+        manager.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
+            mBatteryMeterView = ((BatteryMeterView) fragment.getView().findViewById(
+                    R.id.battery));
 
-        // By default, the BatteryMeterView should not be visible. It will be toggled visible
-        // when a device has connected by bluetooth.
-        mBatteryMeterView.setVisibility(View.GONE);
+            // By default, the BatteryMeterView should not be visible. It will be toggled
+            // when a device has connected by bluetooth.
+            mBatteryMeterView.setVisibility(View.GONE);
 
-        ViewStub stub = (ViewStub) statusBarView.findViewById(R.id.connected_device_signals_stub);
-        View signalsView = stub.inflate();
+            ViewStub stub = (ViewStub) fragment.getView().findViewById(
+                    R.id.connected_device_signals_stub);
+            View signalsView = stub.inflate();
 
-        // When a ViewStub if inflated, it does not respect the margins on the inflated view.
-        // As a result, manually add the ending margin.
-        ((LinearLayout.LayoutParams) signalsView.getLayoutParams()).setMarginEnd(
-                mContext.getResources().getDimensionPixelOffset(
-                        R.dimen.status_bar_connected_device_signal_margin_end));
+            // When a ViewStub if inflated, it does not respect the margins on the
+            // inflated view.
+            // As a result, manually add the ending margin.
+            ((LinearLayout.LayoutParams) signalsView.getLayoutParams()).setMarginEnd(
+                    mContext.getResources().getDimensionPixelOffset(
+                            R.dimen.status_bar_connected_device_signal_margin_end));
 
-        mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
-                signalsView);
+            if (mConnectedDeviceSignalController != null) {
+                mConnectedDeviceSignalController.stopListening();
+            }
+            mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
+                    signalsView);
+            mConnectedDeviceSignalController.startListening();
 
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
-        }
-
-        return statusBarView;
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
+            }
+        });
     }
 
     private BatteryController createBatteryController() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 03c7325..e5f32df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -105,6 +105,11 @@
     }
 
     @Override
+    protected boolean shouldClearBackgroundOnReapply() {
+        return false;
+    }
+
+    @Override
     public int getCustomBackgroundColor() {
         int customBackgroundColor = super.getCustomBackgroundColor();
         if (customBackgroundColor == 0 && mShowingLegacyBackground) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 836482a..5f5e1e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -93,7 +93,9 @@
     public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
         mDarkInitialized = false;
         Drawable background = mView.getBackground();
-        mBackgroundColor = 0;
+        if (shouldClearBackgroundOnReapply()) {
+            mBackgroundColor = 0;
+        }
         if (background instanceof ColorDrawable) {
             mBackgroundColor = ((ColorDrawable) background).getColor();
             mView.setBackground(null);
@@ -101,6 +103,10 @@
         mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
     }
 
+    protected boolean shouldClearBackgroundOnReapply() {
+        return true;
+    }
+
     private boolean isColorLight(int backgroundColor) {
         return Color.alpha(backgroundColor) == 0
                 || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
new file mode 100644
index 0000000..1f56c56
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.statusbar.phone.StatusBar.reinflateSignalCluster;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.app.StatusBarManager;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.EncryptionHelper;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+/**
+ * Contains the collapsed status bar and handles hiding/showing based on disable flags
+ * and keyguard state. Also manages lifecycle to make sure the views it contains are being
+ * updated by the StatusBarIconController and DarkIconManager while it is attached.
+ */
+public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks {
+
+    public static final String TAG = "CollapsedStatusBarFragment";
+    private PhoneStatusBarView mStatusBar;
+    private KeyguardMonitor mKeyguardMonitor;
+    private NetworkController mNetworkController;
+    private LinearLayout mSystemIconArea;
+    private View mNotificationIconAreaInner;
+    private int mDisabled1;
+    private StatusBar mStatusBarComponent;
+    private DarkIconManager mDarkIconManager;
+    private SignalClusterView mSignalClusterView;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+        mNetworkController = Dependency.get(NetworkController.class);
+        mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.status_bar, container, false);
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mStatusBar = (PhoneStatusBarView) view;
+        mDarkIconManager = new DarkIconManager((LinearLayout) view.findViewById(R.id.statusIcons));
+        Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
+        mSystemIconArea = (LinearLayout) mStatusBar.findViewById(R.id.system_icon_area);
+        mSignalClusterView = reinflateSignalCluster(mStatusBar);
+        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSignalClusterView);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSignalClusterView);
+        Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
+    }
+
+    public void initNotificationIconArea(NotificationIconAreaController
+            notificationIconAreaController) {
+        ViewGroup notificationIconArea = (ViewGroup) mStatusBar
+                .findViewById(R.id.notification_icon_area);
+        mNotificationIconAreaInner =
+                notificationIconAreaController.getNotificationInnerAreaView();
+        if (mNotificationIconAreaInner.getParent() != null) {
+            ((ViewGroup) mNotificationIconAreaInner.getParent())
+                    .removeView(mNotificationIconAreaInner);
+        }
+        notificationIconArea.addView(mNotificationIconAreaInner);
+    }
+
+    @Override
+    public void disable(int state1, int state2, boolean animate) {
+        state1 = adjustDisableFlags(state1);
+        final int old1 = mDisabled1;
+        final int diff1 = state1 ^ old1;
+        mDisabled1 = state1;
+        if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+            if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+                hideSystemIconArea(animate);
+            } else {
+                showSystemIconArea(animate);
+            }
+        }
+        if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                hideNotificationIconArea(animate);
+            } else {
+                showNotificationIconArea(animate);
+            }
+        }
+    }
+
+    protected int adjustDisableFlags(int state) {
+        if (!mStatusBarComponent.isLaunchTransitionFadingAway()
+                && !mKeyguardMonitor.isKeyguardFadingAway()
+                && shouldHideNotificationIcons()) {
+            state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+            state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+        }
+        if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
+            if (mNetworkController.hasEmergencyCryptKeeperText()) {
+                state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+            }
+            if (!mNetworkController.isRadioOn()) {
+                state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+            }
+        }
+        return state;
+    }
+
+    private boolean shouldHideNotificationIcons() {
+        return !mStatusBar.isClosed() && mStatusBarComponent.shouldHideNotificationIcons();
+    }
+
+    public void hideSystemIconArea(boolean animate) {
+        animateHide(mSystemIconArea, animate);
+    }
+
+    public void showSystemIconArea(boolean animate) {
+        animateShow(mSystemIconArea, animate);
+    }
+
+    public void hideNotificationIconArea(boolean animate) {
+        animateHide(mNotificationIconAreaInner, animate);
+    }
+
+    public void showNotificationIconArea(boolean animate) {
+        animateShow(mNotificationIconAreaInner, animate);
+    }
+
+    /**
+     * Hides a view.
+     */
+    private void animateHide(final View v, boolean animate) {
+        v.animate().cancel();
+        if (!animate) {
+            v.setAlpha(0f);
+            v.setVisibility(View.INVISIBLE);
+            return;
+        }
+        v.animate()
+                .alpha(0f)
+                .setDuration(160)
+                .setStartDelay(0)
+                .setInterpolator(Interpolators.ALPHA_OUT)
+                .withEndAction(() -> v.setVisibility(View.INVISIBLE));
+    }
+
+    /**
+     * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
+     */
+    private void animateShow(View v, boolean animate) {
+        v.animate().cancel();
+        v.setVisibility(View.VISIBLE);
+        if (!animate) {
+            v.setAlpha(1f);
+            return;
+        }
+        v.animate()
+                .alpha(1f)
+                .setDuration(320)
+                .setInterpolator(Interpolators.ALPHA_IN)
+                .setStartDelay(50)
+
+                // We need to clean up any pending end action from animateHide if we call
+                // both hide and show in the same frame before the animation actually gets started.
+                // cancel() doesn't really remove the end action.
+                .withEndAction(null);
+
+        // Synchronize the motion with the Keyguard fading if necessary.
+        if (mKeyguardMonitor.isKeyguardFadingAway()) {
+            v.animate()
+                    .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration())
+                    .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
+                    .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
+                    .start();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
new file mode 100644
index 0000000..020dc25
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.res.Configuration;
+
+import com.android.systemui.ConfigurationChangedReceiver;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
+import java.util.ArrayList;
+
+public class ConfigurationControllerImpl implements ConfigurationController,
+        ConfigurationChangedReceiver {
+
+    private final ArrayList<ConfigurationListener> mListeners = new ArrayList<>();
+    private int mDensity;
+    private float mFontScale;
+
+    public ConfigurationControllerImpl(Context context) {
+        Configuration currentConfig = context.getResources().getConfiguration();
+        mFontScale = currentConfig.fontScale;
+        mDensity = currentConfig.densityDpi;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        mListeners.forEach(l -> l.onConfigChanged(newConfig));
+        final float fontScale = newConfig.fontScale;
+        final int density = newConfig.densityDpi;
+        if (density != mDensity || mFontScale != fontScale) {
+            mListeners.forEach(l -> l.onDensityOrFontScaleChanged());
+            mDensity = density;
+            mFontScale = fontScale;
+        }
+    }
+
+    @Override
+    public void addCallback(ConfigurationListener listener) {
+        mListeners.add(listener);
+        listener.onDensityOrFontScaleChanged();
+    }
+
+    @Override
+    public void removeCallback(ConfigurationListener listener) {
+        mListeners.remove(listener);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
new file mode 100644
index 0000000..3f9ae80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+
+import android.animation.ArgbEvaluator;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+
+public class DarkIconDispatcherImpl implements DarkIconDispatcher {
+
+    private final LightBarTransitionsController mTransitionsController;
+    private final Rect mTintArea = new Rect();
+    private final ArrayMap<Object, DarkReceiver> mReceivers = new ArrayMap<>();
+
+    private int mIconTint = DEFAULT_ICON_TINT;
+    private float mDarkIntensity;
+    private int mDarkModeIconColorSingleTone;
+    private int mLightModeIconColorSingleTone;
+
+    public DarkIconDispatcherImpl(Context context) {
+        mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
+        mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
+
+        mTransitionsController = new LightBarTransitionsController(context,
+                this::setIconTintInternal);
+    }
+
+    public LightBarTransitionsController getTransitionsController() {
+        return mTransitionsController;
+    }
+
+    public void addDarkReceiver(DarkReceiver receiver) {
+        mReceivers.put(receiver, receiver);
+        receiver.onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+    }
+
+    public void addDarkReceiver(ImageView imageView) {
+        DarkReceiver receiver = (area, darkIntensity, tint) -> imageView.setImageTintList(
+                ColorStateList.valueOf(getTint(mTintArea, imageView, mIconTint)));
+        mReceivers.put(imageView, receiver);
+        receiver.onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+    }
+
+    public void removeDarkReceiver(DarkReceiver object) {
+        mReceivers.remove(object);
+    }
+
+    public void removeDarkReceiver(ImageView object) {
+        mReceivers.remove(object);
+    }
+
+    public void applyDark(ImageView object) {
+        mReceivers.get(object).onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+    }
+
+    /**
+     * Sets the dark area so {@link #setIconsDark} only affects the icons in the specified area.
+     *
+     * @param darkArea the area in which icons should change it's tint, in logical screen
+     *                 coordinates
+     */
+    public void setIconsDarkArea(Rect darkArea) {
+        if (darkArea == null && mTintArea.isEmpty()) {
+            return;
+        }
+        if (darkArea == null) {
+            mTintArea.setEmpty();
+        } else {
+            mTintArea.set(darkArea);
+        }
+        applyIconTint();
+    }
+
+    private void setIconTintInternal(float darkIntensity) {
+        mDarkIntensity = darkIntensity;
+        mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
+                mLightModeIconColorSingleTone, mDarkModeIconColorSingleTone);
+        applyIconTint();
+    }
+
+    private void applyIconTint() {
+        for (int i = 0; i < mReceivers.size(); i++) {
+            mReceivers.valueAt(i).onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 0773108..2bb3cbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -27,6 +27,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.LatencyTracker;
+import com.android.systemui.Dependency;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 
 /**
@@ -101,7 +102,6 @@
     private int mPendingAuthenticatedUserId = -1;
 
     public FingerprintUnlockController(Context context,
-            StatusBarWindowManager statusBarWindowManager,
             DozeScrimController dozeScrimController,
             KeyguardViewMediator keyguardViewMediator,
             ScrimController scrimController,
@@ -111,7 +111,7 @@
         mPowerManager = context.getSystemService(PowerManager.class);
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
         mUpdateMonitor.registerCallback(this);
-        mStatusBarWindowManager = statusBarWindowManager;
+        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
         mDozeScrimController = dozeScrimController;
         mKeyguardViewMediator = keyguardViewMediator;
         mScrimController = scrimController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 4535992..9d699cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -20,7 +20,12 @@
 import android.view.View;
 
 import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
@@ -28,11 +33,11 @@
 /**
  * Controls how light status bar flag applies to the icons.
  */
-public class LightBarController implements BatteryController.BatteryStateChangeCallback {
+public class LightBarController implements BatteryController.BatteryStateChangeCallback, Dumpable {
 
     private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
 
-    private final StatusBarIconController mStatusBarIconController;
+    private final DarkIconDispatcher mStatusBarIconController;
     private final BatteryController mBatteryController;
     private FingerprintUnlockController mFingerprintUnlockController;
 
@@ -61,8 +66,8 @@
     private final Rect mLastFullscreenBounds = new Rect();
     private final Rect mLastDockedBounds = new Rect();
 
-    public LightBarController(StatusBarIconController statusBarIconController) {
-        mStatusBarIconController = statusBarIconController;
+    public LightBarController() {
+        mStatusBarIconController = Dependency.get(DarkIconDispatcher.class);
         mBatteryController = Dependency.get(BatteryController.class);
         mBatteryController.addCallback(this);
     }
@@ -203,4 +208,37 @@
     public void onPowerSaveChanged(boolean isPowerSave) {
         reevaluate();
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("LightBarController: ");
+        pw.print(" mSystemUiVisibility=0x"); pw.print(
+                Integer.toHexString(mSystemUiVisibility));
+        pw.print(" mFullscreenStackVisibility=0x"); pw.print(
+                Integer.toHexString(mFullscreenStackVisibility));
+        pw.print(" mDockedStackVisibility=0x"); pw.println(
+                Integer.toHexString(mDockedStackVisibility));
+
+        pw.print(" mFullscreenLight="); pw.print(mFullscreenLight);
+        pw.print(" mDockedLight="); pw.println(mDockedLight);
+
+        pw.print(" mLastFullscreenBounds="); pw.print(mLastFullscreenBounds);
+        pw.print(" mLastDockedBounds="); pw.println(mLastDockedBounds);
+
+        pw.print(" mNavigationLight="); pw.print(mNavigationLight);
+        pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar);
+
+        pw.print(" mLastStatusBarMode="); pw.print(mLastStatusBarMode);
+        pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode);
+
+        pw.print(" mScrimAlpha="); pw.print(mScrimAlpha);
+        pw.print(" mScrimAlphaBelowThreshold="); pw.println(mScrimAlphaBelowThreshold);
+        pw.println();
+        pw.println(" StatusBarTransitionsController:");
+        mStatusBarIconController.getTransitionsController().dump(fd, pw, args);
+        pw.println();
+        pw.println(" NavigationBarTransitionsController:");
+        mNavigationBarController.dump(fd, pw, args);
+        pw.println();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 0f9f056..6bd959f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -17,22 +17,34 @@
 package com.android.systemui.statusbar.phone;
 
 import android.animation.ValueAnimator;
+import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.util.TimeUtils;
 
+import com.android.systemui.Dumpable;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
 /**
  * Class to control all aspects about light bar changes.
  */
-public class LightBarTransitionsController {
+public class LightBarTransitionsController implements Dumpable, Callbacks {
 
     public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
     private static final String EXTRA_DARK_INTENSITY = "dark_intensity";
 
     private final Handler mHandler;
     private final DarkIntensityApplier mApplier;
+    private final KeyguardMonitor mKeyguardMonitor;
 
     private boolean mTransitionDeferring;
     private long mTransitionDeferringStartTime;
@@ -51,9 +63,17 @@
         }
     };
 
-    public LightBarTransitionsController(DarkIntensityApplier applier) {
+    public LightBarTransitionsController(Context context, DarkIntensityApplier applier) {
         mApplier = applier;
         mHandler = new Handler();
+        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+        SysUiServiceProvider.getComponent(context, CommandQueue.class)
+                .addCallbacks(this);
+    }
+
+    public void destroy(Context context) {
+        SysUiServiceProvider.getComponent(context, CommandQueue.class)
+                .removeCallbacks(this);
     }
 
     public void saveState(Bundle outState) {
@@ -66,10 +86,15 @@
         setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0));
     }
 
-    public void appTransitionPending() {
+    @Override
+    public void appTransitionPending(boolean forced) {
+        if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
+            return;
+        }
         mTransitionPending = true;
     }
 
+    @Override
     public void appTransitionCancelled() {
         if (mTransitionPending && mTintChangePending) {
             mTintChangePending = false;
@@ -78,7 +103,11 @@
         mTransitionPending = false;
     }
 
-    public void appTransitionStarting(long startTime, long duration) {
+    @Override
+    public void appTransitionStarting(long startTime, long duration, boolean forced) {
+        if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
+            return;
+        }
         if (mTransitionPending && mTintChangePending) {
             mTintChangePending = false;
             animateIconTint(mPendingDarkIntensity,
@@ -147,6 +176,26 @@
         mApplier.applyDarkIntensity(darkIntensity);
     }
 
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.print("  mTransitionDeferring="); pw.print(mTransitionDeferring);
+        if (mTransitionDeferring) {
+            pw.println();
+            pw.print("   mTransitionDeferringStartTime=");
+            pw.println(TimeUtils.formatUptime(mTransitionDeferringStartTime));
+
+            pw.print("   mTransitionDeferringDuration=");
+            TimeUtils.formatDuration(mTransitionDeferringDuration, pw);
+            pw.println();
+        }
+        pw.print("  mTransitionPending="); pw.print(mTransitionPending);
+        pw.print(" mTintChangePending="); pw.println(mTintChangePending);
+
+        pw.print("  mPendingDarkIntensity="); pw.print(mPendingDarkIntensity);
+        pw.print(" mDarkIntensity="); pw.print(mDarkIntensity);
+        pw.print(" mNextDarkIntensity="); pw.println(mNextDarkIntensity);
+    }
+
     /**
      * Interface to apply a specific dark intensity.
      */
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 62b536e..99f8aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
 import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -79,6 +80,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -101,7 +103,7 @@
 
     private int mNavigationIconHints = 0;
     private int mNavigationBarMode;
-    protected AccessibilityManager mAccessibilityManager;
+    private AccessibilityManager mAccessibilityManager;
 
     private int mDisabledFlags1;
     private StatusBar mStatusBar;
@@ -116,7 +118,6 @@
 
     private int mSystemUiVisibility;
     private LightBarController mLightBarController;
-    private boolean mKeyguardGoingAway;
 
     public boolean mHomeBlockedThisTouch;
 
@@ -132,6 +133,8 @@
         mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
         mWindowManager = getContext().getSystemService(WindowManager.class);
         mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
+        mAccessibilityManager.addAccessibilityServicesStateChangeListener(
+                this::updateAccessibilityServicesState);
         if (savedInstanceState != null) {
             mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
         }
@@ -149,6 +152,8 @@
     public void onDestroy() {
         super.onDestroy();
         mCommandQueue.removeCallbacks(this);
+        mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
+                this::updateAccessibilityServicesState);
         try {
             WindowManagerGlobal.getWindowManagerService()
                     .removeRotationWatcher(mRotationWatcher);
@@ -189,6 +194,7 @@
     @Override
     public void onDestroyView() {
         super.onDestroyView();
+        mNavigationBarView.getLightTransitionsController().destroy(getContext());
         getContext().unregisterReceiver(mBroadcastReceiver);
     }
 
@@ -281,31 +287,6 @@
         }
     }
 
-    @Override
-    public void appTransitionPending() {
-        mNavigationBarView.getLightTransitionsController().appTransitionPending();
-    }
-
-    @Override
-    public void appTransitionCancelled() {
-        mNavigationBarView.getLightTransitionsController().appTransitionCancelled();
-    }
-
-    @Override
-    public void appTransitionStarting(long startTime, long duration) {
-        if (mKeyguardGoingAway) return;
-        doAppTransitionStarting(startTime, duration);
-    }
-
-    /**
-     * Calls appTransitionStarting for the nav bar regardless of whether keyguard is going away.
-     * public so StatusBar can force this when needed.
-     */
-    public void doAppTransitionStarting(long startTime, long duration) {
-        mNavigationBarView.getLightTransitionsController().appTransitionStarting(startTime,
-                duration);
-    }
-
     // Injected from StatusBar at creation.
     public void setCurrentSysuiVisibility(int systemUiVisibility) {
         mSystemUiVisibility = systemUiVisibility;
@@ -402,6 +383,10 @@
         ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
         homeButton.setOnTouchListener(this::onHomeTouch);
         homeButton.setOnLongClickListener(this::onHomeLongClick);
+
+        ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
+        accessibilityButton.setOnClickListener(this::onAccessibilityClick);
+        accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
     }
 
     private boolean onHomeTouch(View v, MotionEvent event) {
@@ -553,6 +538,34 @@
                 MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
     }
 
+    private void onAccessibilityClick(View v) {
+        mAccessibilityManager.notifyAccessibilityButtonClicked();
+    }
+
+    private boolean onAccessibilityLongClick(View v) {
+        // TODO(b/34720082): Target service selection via long click
+        android.widget.Toast.makeText(getContext(), "Service selection coming soon...",
+                android.widget.Toast.LENGTH_LONG).show();
+        return true;
+    }
+
+    private void updateAccessibilityServicesState() {
+        final List<AccessibilityServiceInfo> services =
+                mAccessibilityManager.getEnabledAccessibilityServiceList(
+                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+        int requestingServices = 0;
+        for (int i = services.size() - 1; i >= 0; --i) {
+            AccessibilityServiceInfo info = services.get(i);
+            if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
+                requestingServices++;
+            }
+        }
+
+        final boolean showAccessibilityButton = requestingServices >= 1;
+        final boolean targetSelection = requestingServices >= 2;
+        mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
+    }
+
     // ----- Methods that StatusBar talks to (should be minimized) -----
 
     public void setLightBarController(LightBarController lightBarController) {
@@ -574,10 +587,6 @@
                 delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
     }
 
-    public void setKeyguardGoingAway(boolean keyguardGoingAway) {
-        mKeyguardGoingAway = keyguardGoingAway;
-    }
-
     public BarTransitions getBarTransitions() {
         return mNavigationBarView.getBarTransitions();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 3be5e57..cb925d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -38,7 +38,8 @@
         mView = view;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        mLightTransitionsController = new LightBarTransitionsController(this::applyDarkIntensity);
+        mLightTransitionsController = new LightBarTransitionsController(view.getContext(),
+                this::applyDarkIntensity);
     }
 
     public void init() {
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 dced747..5d13289 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -78,6 +78,8 @@
     private int mCurrentRotation = -1;
 
     boolean mShowMenu;
+    boolean mShowAccessibilityButton;
+    boolean mLongClickableAccessibilityButton;
     int mDisabledFlags = 0;
     int mNavigationIconHints = 0;
 
@@ -89,6 +91,7 @@
     private KeyButtonDrawable mDockedIcon;
     private KeyButtonDrawable mImeIcon;
     private KeyButtonDrawable mMenuIcon;
+    private KeyButtonDrawable mAccessibilityIcon;
 
     private GestureHelper mGestureHelper;
     private DeadZone mDeadZone;
@@ -202,6 +205,9 @@
         mVertical = false;
         mShowMenu = false;
 
+        mShowAccessibilityButton = false;
+        mLongClickableAccessibilityButton = false;
+
         mConfiguration = new Configuration();
         mConfiguration.updateFrom(context.getResources().getConfiguration());
         updateIcons(context, Configuration.EMPTY, mConfiguration);
@@ -213,6 +219,8 @@
         mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
         mButtonDispatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
         mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
+        mButtonDispatchers.put(R.id.accessibility_button,
+                new ButtonDispatcher(R.id.accessibility_button));
     }
 
     public BarTransitions getBarTransitions() {
@@ -287,6 +295,10 @@
         return mButtonDispatchers.get(R.id.ime_switcher);
     }
 
+    public ButtonDispatcher getAccessibilityButton() {
+        return mButtonDispatchers.get(R.id.accessibility_button);
+    }
+
     public SparseArray<ButtonDispatcher> getButtonDispatchers() {
         return mButtonDispatchers;
     }
@@ -320,6 +332,8 @@
             mRecentIcon = getDrawable(ctx,
                     R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
             mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
+            mAccessibilityIcon = getDrawable(ctx, R.drawable.ic_sysbar_accessibility_button,
+                    R.drawable.ic_sysbar_accessibility_button_dark);
 
             Context darkContext = new ContextThemeWrapper(ctx, R.style.DualToneDarkTheme);
             Context lightContext = new ContextThemeWrapper(ctx, R.style.DualToneLightTheme);
@@ -411,6 +425,9 @@
         setMenuVisibility(mShowMenu, true);
         getMenuButton().setImageDrawable(mMenuIcon);
 
+        setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
+        getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
+
         setDisabledFlags(mDisabledFlags, true);
 
         mBarTransitions.reapplyDarkIntensity();
@@ -517,13 +534,25 @@
 
         mShowMenu = show;
 
-        // Only show Menu if IME switcher not shown.
-        final boolean shouldShow = mShowMenu &&
+        // Only show Menu if IME switcher and Accessibility button not shown.
+        final boolean shouldShow = mShowMenu && !mShowAccessibilityButton &&
                 ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
 
         getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
     }
 
+    public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
+        mShowAccessibilityButton = visible;
+        mLongClickableAccessibilityButton = longClickable;
+        if (visible) {
+            // Accessibility button overrides Menu button.
+            setMenuVisibility(false, true);
+        }
+
+        getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        getAccessibilityButton().setLongClickable(longClickable);
+    }
+
     @Override
     public void onFinishInflate() {
         mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
@@ -814,6 +843,7 @@
         dumpButton(pw, "home", getHomeButton());
         dumpButton(pw, "rcnt", getRecentsButton());
         dumpButton(pw, "menu", getMenuButton());
+        dumpButton(pw, "a11y", getAccessibilityButton());
 
         pw.println("    }");
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 0386398..6d7ab47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -17,6 +17,8 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
@@ -26,7 +28,7 @@
  * A controller for the space in the status bar to the left of the system icons. This area is
  * normally reserved for notifications.
  */
-public class NotificationIconAreaController {
+public class NotificationIconAreaController implements DarkReceiver {
     private final NotificationColorUtil mNotificationColorUtil;
 
     private int mIconSize;
@@ -64,11 +66,12 @@
         mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(
                 R.id.notificationIcons);
 
-        NotificationShelf shelf = mStatusBar.getNotificationShelf();
+        mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
+    }
+
+    public void setupShelf(NotificationShelf shelf) {
         mShelfIcons = shelf.getShelfIcons();
         shelf.setCollapsedIcons(mNotificationIcons);
-
-        mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
     }
 
     public void onDensityOrFontScaleChanged(Context context) {
@@ -102,23 +105,18 @@
     }
 
     /**
-     * See {@link StatusBarIconController#setIconsDarkArea}.
+     * See {@link com.android.systemui.statusbar.policy.DarkIconDispatcher#setIconsDarkArea}.
+     * Sets the color that should be used to tint any icons in the notification area.
      *
      * @param tintArea the area in which to tint the icons, specified in screen coordinates
+     * @param darkIntensity
      */
-    public void setTintArea(Rect tintArea) {
+    public void onDarkChanged(Rect tintArea, float darkIntensity, int iconTint) {
         if (tintArea == null) {
             mTintArea.setEmpty();
         } else {
             mTintArea.set(tintArea);
         }
-        applyNotificationIconsTint();
-    }
-
-    /**
-     * Sets the color that should be used to tint any icons in the notification area.
-     */
-    public void setIconTint(int iconTint) {
         mIconTint = iconTint;
         applyNotificationIconsTint();
     }
@@ -231,7 +229,7 @@
             boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
             if (colorize) {
                 v.setImageTintList(ColorStateList.valueOf(
-                        StatusBarIconController.getTint(mTintArea, v, mIconTint)));
+                        DarkIconDispatcher.getTint(mTintArea, v, mIconTint)));
             }
             v.setIconTint(mIconTint);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index c25a45c..571ae26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -104,6 +104,7 @@
     private float mOpenedAmount = 0.0f;
     private float mVisualOverflowAdaption;
     private boolean mDisallowNextAnimation;
+    private boolean mAnimationsEnabled = true;
 
     public NotificationIconContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -255,7 +256,7 @@
             iconState.visibleState = StatusBarIconView.STATE_ICON;
             if (firstOverflowIndex == -1 && (isAmbient
                     || (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart)))) {
-                firstOverflowIndex = noOverflowAfter ? i - 1 : i;
+                firstOverflowIndex = noOverflowAfter && !isAmbient ? i - 1 : i;
                 int totalDotLength = mStaticDotRadius * 6 + 2 * mDotPadding;
                 visualOverflowStart = overflowStart + mIconSize * (1 + OVERFLOW_EARLY_AMOUNT)
                         - totalDotLength / 2
@@ -422,6 +423,20 @@
         return mIconSize;
     }
 
+    public void setAnimationsEnabled(boolean enabled) {
+        if (!enabled && mAnimationsEnabled) {
+            for (int i = 0; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                ViewState childState = mIconStates.get(child);
+                if (childState != null) {
+                    childState.cancelAnimations(child);
+                    childState.applyToView(child);
+                }
+            }
+        }
+        mAnimationsEnabled = enabled;
+    }
+
     public class IconState extends ViewState {
         public float iconAppearAmount = 1.0f;
         public float clampedAppearAmount = 1.0f;
@@ -438,52 +453,59 @@
                 StatusBarIconView icon = (StatusBarIconView) view;
                 boolean animate = false;
                 AnimationProperties animationProperties = null;
-                if (justAdded) {
-                    super.applyToView(icon);
-                    icon.setAlpha(0.0f);
-                    icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, false /* animate */);
-                    animationProperties = ADD_ICON_PROPERTIES;
-                    animate = true;
-                } else if (visibleState != icon.getVisibleState()) {
-                    animationProperties = DOT_ANIMATION_PROPERTIES;
-                    animate = true;
-                }
-                if (!animate && mAddAnimationStartIndex >= 0
-                        && indexOfChild(view) >= mAddAnimationStartIndex
-                        && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
-                            || visibleState != StatusBarIconView.STATE_HIDDEN)) {
-                    animationProperties = DOT_ANIMATION_PROPERTIES;
-                    animate = true;
-                }
-                if (needsCannedAnimation) {
-                    AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
-                    animationFilter.reset();
-                    animationFilter.combineFilter(ICON_ANIMATION_PROPERTIES.getAnimationFilter());
-                    mTempProperties.resetCustomInterpolators();
-                    mTempProperties.combineCustomInterpolators(ICON_ANIMATION_PROPERTIES);
-                    if (animationProperties != null) {
-                        animationFilter.combineFilter(animationProperties.getAnimationFilter());
-                        mTempProperties.combineCustomInterpolators(animationProperties);
+                boolean animationsAllowed = mAnimationsEnabled && !mDisallowNextAnimation;
+                if (animationsAllowed) {
+                    if (justAdded) {
+                        super.applyToView(icon);
+                        if (iconAppearAmount != 0.0f) {
+                            icon.setAlpha(0.0f);
+                            icon.setVisibleState(StatusBarIconView.STATE_HIDDEN,
+                                    false /* animate */);
+                            animationProperties = ADD_ICON_PROPERTIES;
+                            animate = true;
+                        }
+                    } else if (visibleState != icon.getVisibleState()) {
+                        animationProperties = DOT_ANIMATION_PROPERTIES;
+                        animate = true;
                     }
-                    animationProperties = mTempProperties;
-                    animationProperties.setDuration(CANNED_ANIMATION_DURATION);
-                    animate = true;
-                    mCannedAnimationStartIndex = indexOfChild(view);
+                    if (!animate && mAddAnimationStartIndex >= 0
+                            && indexOfChild(view) >= mAddAnimationStartIndex
+                            && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+                            || visibleState != StatusBarIconView.STATE_HIDDEN)) {
+                        animationProperties = DOT_ANIMATION_PROPERTIES;
+                        animate = true;
+                    }
+                    if (needsCannedAnimation) {
+                        AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
+                        animationFilter.reset();
+                        animationFilter.combineFilter(
+                                ICON_ANIMATION_PROPERTIES.getAnimationFilter());
+                        mTempProperties.resetCustomInterpolators();
+                        mTempProperties.combineCustomInterpolators(ICON_ANIMATION_PROPERTIES);
+                        if (animationProperties != null) {
+                            animationFilter.combineFilter(animationProperties.getAnimationFilter());
+                            mTempProperties.combineCustomInterpolators(animationProperties);
+                        }
+                        animationProperties = mTempProperties;
+                        animationProperties.setDuration(CANNED_ANIMATION_DURATION);
+                        animate = true;
+                        mCannedAnimationStartIndex = indexOfChild(view);
+                    }
+                    if (!animate && mCannedAnimationStartIndex >= 0
+                            && indexOfChild(view) > mCannedAnimationStartIndex
+                            && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+                            || visibleState != StatusBarIconView.STATE_HIDDEN)) {
+                        AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
+                        animationFilter.reset();
+                        animationFilter.animateX();
+                        mTempProperties.resetCustomInterpolators();
+                        animationProperties = mTempProperties;
+                        animationProperties.setDuration(CANNED_ANIMATION_DURATION);
+                        animate = true;
+                    }
                 }
-                if (!animate && mCannedAnimationStartIndex >= 0
-                        && indexOfChild(view) > mCannedAnimationStartIndex
-                        && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
-                        || visibleState != StatusBarIconView.STATE_HIDDEN)) {
-                    AnimationFilter animationFilter = mTempProperties.getAnimationFilter();
-                    animationFilter.reset();
-                    animationFilter.animateX();
-                    mTempProperties.resetCustomInterpolators();
-                    animationProperties = mTempProperties;
-                    animationProperties.setDuration(CANNED_ANIMATION_DURATION);
-                    animate = true;
-                }
-                icon.setVisibleState(visibleState);
-                if (animate && !mDisallowNextAnimation) {
+                icon.setVisibleState(visibleState, animationsAllowed);
+                if (animate) {
                     animateTo(icon, animationProperties);
                 } else {
                     super.applyToView(view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 87a3848..23d3816 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -166,6 +166,10 @@
         if (DEBUG) LOG("onPanelPeeked");
     }
 
+    public boolean isClosed() {
+        return mState == STATE_CLOSED;
+    }
+
     public void onPanelCollapsed() {
         if (DEBUG) LOG("onPanelCollapsed");
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 1044ecf..93f874d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -38,24 +38,35 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.BluetoothController.Callback;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.DataSaverController.Listener;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
 import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 
 /**
  * This class contains all of the policy about which icons are installed in the status
  * bar at boot time.  It goes through the normal API for icons, even though it probably
  * strictly doesn't need to.
  */
-public class PhoneStatusBarPolicy implements Callback, RotationLockController.RotationLockControllerCallback, DataSaverController.Listener {
+public class PhoneStatusBarPolicy implements Callback, Callbacks,
+        RotationLockControllerCallback, Listener,
+        ZenModeController.Callback, DeviceProvisionedListener, KeyguardMonitor.Callback {
     private static final String TAG = "PhoneStatusBarPolicy";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -82,7 +93,9 @@
     private final StatusBarIconController mIconController;
     private final RotationLockController mRotationLockController;
     private final DataSaverController mDataSaver;
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private final ZenModeController mZenController;
+    private final DeviceProvisionedController mProvisionedController;
+    private final KeyguardMonitor mKeyguardMonitor;
 
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
@@ -106,13 +119,15 @@
         mCast = Dependency.get(CastController.class);
         mHotspot = Dependency.get(HotspotController.class);
         mBluetooth = Dependency.get(BluetoothController.class);
-        mBluetooth.addCallback(this);
         mNextAlarm = Dependency.get(NextAlarmController.class);
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mUserInfoController = Dependency.get(UserInfoController.class);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mRotationLockController = Dependency.get(RotationLockController.class);
         mDataSaver = Dependency.get(DataSaverController.class);
+        mZenController = Dependency.get(ZenModeController.class);
+        mProvisionedController = Dependency.get(DeviceProvisionedController.class);
+        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
 
         mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
         mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -127,7 +142,6 @@
         mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
         mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
 
-        mRotationLockController.addCallback(this);
 
         // listen for broadcasts
         IntentFilter filter = new IntentFilter();
@@ -158,7 +172,6 @@
         // Alarm clock
         mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
         mIconController.setIconVisibility(mSlotAlarmClock, false);
-        mNextAlarm.addCallback(mNextAlarmCallback);
 
         // zen
         mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
@@ -172,13 +185,11 @@
         // cast
         mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
         mIconController.setIconVisibility(mSlotCast, false);
-        mCast.addCallback(mCastCallback);
 
         // hotspot
         mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
                 mContext.getString(R.string.accessibility_status_bar_hotspot));
         mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
-        mHotspot.addCallback(mHotspotCallback);
 
         // managed profile
         mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
@@ -189,15 +200,36 @@
         mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
                 context.getString(R.string.accessibility_data_saver_on));
         mIconController.setIconVisibility(mSlotDataSaver, false);
+
+        mRotationLockController.addCallback(this);
+        mBluetooth.addCallback(this);
+        mProvisionedController.addCallback(this);
+        mZenController.addCallback(this);
+        mCast.addCallback(mCastCallback);
+        mHotspot.addCallback(mHotspotCallback);
+        mNextAlarm.addCallback(mNextAlarmCallback);
         mDataSaver.addCallback(this);
+        mKeyguardMonitor.addCallback(this);
+
+        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
     }
 
-    public void setStatusBarKeyguardViewManager(
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
-        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+    public void destroy() {
+        mRotationLockController.removeCallback(this);
+        mBluetooth.removeCallback(this);
+        mProvisionedController.removeCallback(this);
+        mZenController.removeCallback(this);
+        mCast.removeCallback(mCastCallback);
+        mHotspot.removeCallback(mHotspotCallback);
+        mNextAlarm.removeCallback(mNextAlarmCallback);
+        mDataSaver.removeCallback(this);
+        mKeyguardMonitor.removeCallback(this);
+        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this);
+        mContext.unregisterReceiver(mIntentReceiver);
     }
 
-    public void setZenMode(int zen) {
+    @Override
+    public void onZenChanged(int zen) {
         mZen = zen;
         updateVolumeZen();
     }
@@ -394,7 +426,7 @@
         if (DEBUG) Log.v(TAG, "updateManagedProfile: mManagedProfileFocused: "
                 + mManagedProfileFocused);
         final boolean showIcon;
-        if (mManagedProfileFocused && !mStatusBarKeyguardViewManager.isShowing()) {
+        if (mManagedProfileFocused && !mKeyguardMonitor.isShowing()) {
             showIcon = true;
             mIconController.setIcon(mSlotManagedProfile,
                     R.drawable.stat_sys_managed_profile_status,
@@ -471,15 +503,20 @@
         }
     };
 
-    public void appTransitionStarting(long startTime, long duration) {
+    @Override
+    public void appTransitionStarting(long startTime, long duration, boolean forced) {
         updateManagedProfile();
     }
 
-    public void notifyKeyguardShowingChanged() {
+    @Override
+    public void onKeyguardShowingChanged() {
         updateManagedProfile();
     }
 
-    public void setCurrentUserSetup(boolean userSetup) {
+    @Override
+    public void onUserSetupChanged() {
+        boolean userSetup = mProvisionedController.isUserSetup(
+                mProvisionedController.getCurrentUser());
         if (mCurrentUserSetup == userSetup) return;
         mCurrentUserSetup = userSetup;
         updateAlarm();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 7e08812..b52c26f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -24,9 +24,13 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
@@ -48,6 +52,7 @@
             }
         }
     };
+    private DarkReceiver mBattery;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -70,6 +75,20 @@
     @Override
     public void onFinishInflate() {
         mBarTransitions.init();
+        mBattery = (DarkReceiver) findViewById(R.id.battery);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        // Always have Battery meters in the status bar observe the dark/light modes.
+        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 4307a2e..457ed6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -178,7 +178,7 @@
         SignalClusterView cluster = (SignalClusterView) findViewById(R.id.signal_cluster);
         int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
         float intensity = colorForeground == Color.WHITE ? 0 : 1;
-        cluster.setIconTint(colorForeground, intensity, new Rect(0, 0, 0, 0));
+        cluster.onDarkChanged(new Rect(0, 0, 0, 0), intensity, colorForeground);
         BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery);
         int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
         battery.setRawColors(colorForeground, colorSecondary);
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 9ac6f65..365d991 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -173,13 +173,16 @@
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.statusbar.policy.EncryptionHelper;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
@@ -193,6 +196,8 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
 
+
+import com.android.systemui.util.leak.LeakDetector;
 import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
@@ -279,6 +284,9 @@
     protected static final boolean ENABLE_HEADS_UP = true;
     protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
+    // Must match constant in Settings. Used to highlight preferences when linking to Settings.
+    private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+
     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
     // Should match the values in PhoneWindowManager
@@ -501,9 +509,6 @@
                 }
                 updateQsExpansionEnabled();
             }
-            if (mIconPolicy != null) {
-                mIconPolicy.setCurrentUserSetup(mUserSetup);
-            }
         }
     };
 
@@ -603,8 +608,6 @@
             new ArraySet<>();
     private long mLastVisibilityReportUptimeMs;
 
-    private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
-
     private Runnable mLaunchTransitionEndRunnable;
     protected boolean mLaunchTransitionFadingAway;
     private ExpandableNotificationRow mDraggedDownRow;
@@ -711,6 +714,8 @@
     private BatteryController mBatteryController;
     private LogMaker mStatusBarStateLog;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
+    private NotificationIconAreaController mNotificationIconAreaController;
+    private ConfigurationListener mDensityChangeListener;
 
     private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
         final int N = array.size();
@@ -808,8 +813,6 @@
         final Configuration currentConfig = mContext.getResources().getConfiguration();
         mLocale = currentConfig.locale;
         mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
-        mFontScale = currentConfig.fontScale;
-        mDensity = currentConfig.densityDpi;
 
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
@@ -846,7 +849,7 @@
         int N = iconSlots.size();
         int viewIndex = 0;
         for (int i=0; i < N; i++) {
-            setIcon(iconSlots.get(i), icons.get(i));
+            mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
         }
 
         // Set up the initial notification state.
@@ -893,7 +896,8 @@
                 null, null);
         updateCurrentProfilesCache();
 
-        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
+        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
+                Context.VR_SERVICE));
         try {
             vrManager.registerListener(mVrStateCallbacks);
         } catch (RemoteException e) {
@@ -912,7 +916,6 @@
 
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
-        mIconPolicy.setCurrentUserSetup(mUserSetup);
         mSettingsObserver.onChange(false); // set up
 
         mHeadsUpObserver.onChange(true); // set up
@@ -936,18 +939,25 @@
 
         mScreenPinningRequest = new ScreenPinningRequest(mContext);
         mFalsingManager = FalsingManager.getInstance(mContext);
+
         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
+
+        mDensityChangeListener = new ConfigurationListener() {
+            @Override
+            public void onDensityOrFontScaleChanged() {
+                StatusBar.this.onDensityOrFontScaleChanged();
+            }
+        };
+        Dependency.get(ConfigurationController.class).addCallback(mDensityChangeListener);
     }
 
     protected void createIconController() {
-        mIconController = new StatusBarIconController(
-                mContext, mStatusBarView, mKeyguardStatusBar, this);
     }
 
     // ================================================================================
     // Constructing the view
     // ================================================================================
-    protected PhoneStatusBarView makeStatusBarView() {
+    protected void makeStatusBarView() {
         final Context context = mContext;
         updateDisplaySize(); // populates mDisplayMetrics
         updateResources();
@@ -956,14 +966,37 @@
         mStatusBarWindow.setService(this);
         mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
 
+        // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
+        // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
         mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
                 R.id.notification_panel);
+        mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
+                R.id.notification_stack_scroller);
         mNotificationPanel.setStatusBar(this);
         mNotificationPanel.setGroupManager(mGroupManager);
+        mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
 
-        mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
-        mStatusBarView.setBar(this);
-        mStatusBarView.setPanel(mNotificationPanel);
+        mNotificationIconAreaController = SystemUIFactory.getInstance()
+                .createNotificationIconAreaController(context, this);
+        inflateShelf();
+        mNotificationIconAreaController.setupShelf(mNotificationShelf);
+        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
+        FragmentHostManager.get(mStatusBarWindow)
+                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
+                    CollapsedStatusBarFragment statusBarFragment = (CollapsedStatusBarFragment) fragment;
+                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
+                    mStatusBarView = (PhoneStatusBarView) fragment.getView();
+                    mStatusBarView.setBar(this);
+                    mStatusBarView.setPanel(mNotificationPanel);
+                    mStatusBarView.setScrimController(mScrimController);
+                    setAreThereNotifications();
+                }).getFragmentManager()
+                .beginTransaction()
+                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(), CollapsedStatusBarFragment.TAG)
+                .commit();
+        Dependency.get(StatusBarIconController.class).addIconGroup(
+                new IconManager((ViewGroup) mKeyguardStatusBar.findViewById(R.id.statusIcons)));
+        mIconController = Dependency.get(StatusBarIconController.class);
 
         if (!ActivityManager.isHighEndGfx()) {
             mStatusBarWindow.setBackground(null);
@@ -1001,8 +1034,6 @@
         // figure out which pixel-format to use for the status bar.
         mPixelFormat = PixelFormat.OPAQUE;
 
-        mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
-                R.id.notification_stack_scroller);
         mStackScroller.setLongPressListener(getNotificationLongClicker());
         mStackScroller.setStatusBar(this);
         mStackScroller.setGroupManager(mGroupManager);
@@ -1010,7 +1041,6 @@
         mGroupManager.setOnGroupChangeListener(mStackScroller);
         mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
 
-        inflateShelf();
         inflateEmptyShadeView();
         inflateDismissView();
         mExpandedContents = mStackScroller;
@@ -1023,7 +1053,6 @@
             mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
         }
 
-        mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
         mKeyguardStatusView =
                 (KeyguardStatusView) mStatusBarWindow.findViewById(R.id.keyguard_status_view);
         mKeyguardBottomArea =
@@ -1037,8 +1066,6 @@
         // set the initial view visibility
         setAreThereNotifications();
 
-        createIconController();
-
         // TODO: Find better place for this callback.
         mBatteryController.addCallback(new BatteryStateChangeCallback() {
             @Override
@@ -1055,7 +1082,7 @@
             }
         });
 
-        mLightBarController = new LightBarController(mIconController);
+        mLightBarController = new LightBarController();
         if (mNavigationBar != null) {
             mNavigationBar.setLightBarController(mLightBarController);
         }
@@ -1079,7 +1106,6 @@
         }
         mHeadsUpManager.addListener(mScrimController);
         mStackScroller.setScrimController(mScrimController);
-        mStatusBarView.setScrimController(mScrimController);
         mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller,
                 mNotificationPanel);
 
@@ -1185,8 +1211,6 @@
 
         // Private API call to make the shadows look better for Recents
         ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
-
-        return mStatusBarView;
     }
 
     protected void createNavigationBar() {
@@ -1260,12 +1284,13 @@
         }
         // end old BaseStatusBar.onDensityOrFontScaleChanged().
         mScrimController.onDensityOrFontScaleChanged();
-        mStatusBarView.onDensityOrFontScaleChanged();
+        // TODO: Remove this.
+        if (mStatusBarView != null) mStatusBarView.onDensityOrFontScaleChanged();
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.onDensityOrFontScaleChanged();
         }
         inflateSignalClusters();
-        mIconController.onDensityOrFontScaleChanged();
+        mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
         inflateDismissView();
         updateClearAll();
         inflateEmptyShadeView();
@@ -1281,12 +1306,11 @@
     }
 
     private void inflateSignalClusters() {
-        SignalClusterView signalClusterView = reinflateSignalCluster(mStatusBarView);
-        mIconController.setSignalCluster(signalClusterView);
         reinflateSignalCluster(mKeyguardStatusBar);
     }
 
-    private SignalClusterView reinflateSignalCluster(View view) {
+    public static SignalClusterView reinflateSignalCluster(View view) {
+        Context context = view.getContext();
         SignalClusterView signalCluster =
                 (SignalClusterView) view.findViewById(R.id.signal_cluster);
         if (signalCluster != null) {
@@ -1295,12 +1319,12 @@
                 ViewGroup viewParent = (ViewGroup) parent;
                 int index = viewParent.indexOfChild(signalCluster);
                 viewParent.removeView(signalCluster);
-                SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(mContext)
+                SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(context)
                         .inflate(R.layout.signal_cluster_view, viewParent, false);
                 ViewGroup.MarginLayoutParams layoutParams =
                         (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams();
                 layoutParams.setMarginsRelative(
-                        mContext.getResources().getDimensionPixelSize(
+                        context.getResources().getDimensionPixelSize(
                                 R.dimen.signal_cluster_margin_start),
                         0, 0, 0);
                 newCluster.setLayoutParams(layoutParams);
@@ -1424,26 +1448,22 @@
             updateNotifications();
         }
         // end old BaseStatusBar.setZenMode().
-        if (mIconPolicy != null) {
-            mIconPolicy.setZenMode(mode);
-        }
     }
 
     protected void startKeyguard() {
         Trace.beginSection("StatusBar#startKeyguard");
         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mFingerprintUnlockController = new FingerprintUnlockController(mContext,
-                mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
+                mDozeScrimController, keyguardViewMediator,
                 mScrimController, this, UnlockMethodCache.getInstance(mContext));
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
-                getBouncerContainer(), mStatusBarWindowManager, mScrimController,
+                getBouncerContainer(), mScrimController,
                 mFingerprintUnlockController);
         mKeyguardIndicationController.setStatusBarKeyguardViewManager(
                 mStatusBarKeyguardViewManager);
         mKeyguardIndicationController.setUserInfoController(
                 Dependency.get(UserInfoController.class));
         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
-        mIconPolicy.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
 
         mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@@ -1501,7 +1521,7 @@
                     ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
         } else {
             Divider divider = getComponent(Divider.class);
-            if (divider != null && divider.isMinimized()) {
+            if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
                 // Undocking from the minimized state is not supported
                 return false;
             } else {
@@ -1524,16 +1544,6 @@
         }
     }
 
-    @Override
-    public void setIcon(String slot, StatusBarIcon icon) {
-        mIconController.setIcon(slot, icon);
-    }
-
-    @Override
-    public void removeIcon(String slot) {
-        mIconController.removeIcon(slot);
-    }
-
     public UserHandle getCurrentUserHandle() {
         return new UserHandle(mCurrentUserId);
     }
@@ -1894,10 +1904,9 @@
         updateEmptyShadeView();
 
         updateQsExpansionEnabled();
-        mShadeUpdates.check();
 
         // Let's also update the icons
-        mIconController.updateNotificationIcons(mNotificationData);
+        mNotificationIconAreaController.updateNotificationIcons(mNotificationData);
     }
 
     /**
@@ -2078,24 +2087,26 @@
                     hasActiveNotifications() + " clearable=" + clearable);
         }
 
-        final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
-        final boolean showDot = hasActiveNotifications() && !areLightsOn();
-        if (showDot != (nlo.getAlpha() == 1.0f)) {
-            if (showDot) {
-                nlo.setAlpha(0f);
-                nlo.setVisibility(View.VISIBLE);
+        if (mStatusBarView != null) {
+            final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
+            final boolean showDot = hasActiveNotifications() && !areLightsOn();
+            if (showDot != (nlo.getAlpha() == 1.0f)) {
+                if (showDot) {
+                    nlo.setAlpha(0f);
+                    nlo.setVisibility(View.VISIBLE);
+                }
+                nlo.animate()
+                        .alpha(showDot ? 1 : 0)
+                        .setDuration(showDot ? 750 : 250)
+                        .setInterpolator(new AccelerateInterpolator(2.0f))
+                        .setListener(showDot ? null : new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationEnd(Animator _a) {
+                                nlo.setVisibility(View.GONE);
+                            }
+                        })
+                        .start();
             }
-            nlo.animate()
-                .alpha(showDot?1:0)
-                .setDuration(showDot?750:250)
-                .setInterpolator(new AccelerateInterpolator(2.0f))
-                .setListener(showDot ? null : new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator _a) {
-                        nlo.setVisibility(View.GONE);
-                    }
-                })
-                .start();
         }
 
         findAndUpdateMediaNotifications();
@@ -2419,26 +2430,6 @@
                 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
     }
 
-    protected int adjustDisableFlags(int state) {
-        if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway && shouldHideNotificationIcons()) {
-            state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
-            state |= StatusBarManager.DISABLE_SYSTEM_INFO;
-        }
-        if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
-            if (mNetworkController.hasEmergencyCryptKeeperText()) {
-                state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
-            }
-            if (!mNetworkController.isRadioOn()) {
-                state |= StatusBarManager.DISABLE_SYSTEM_INFO;
-            }
-        }
-        return state;
-    }
-
-    private boolean shouldHideNotificationIcons() {
-        return mExpandedVisible && mNotificationPanel.shouldHideNotificationIcons();
-    }
-
     /**
      * State is one or more of the DISABLE constants from StatusBarManager.
      */
@@ -2447,7 +2438,6 @@
         animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
         mDisabledUnmodified1 = state1;
         mDisabledUnmodified2 = state2;
-        state1 = adjustDisableFlags(state1);
         final int old1 = mDisabled1;
         final int diff1 = state1 ^ old1;
         mDisabled1 = state1;
@@ -2489,28 +2479,13 @@
         flagdbg.append(">");
         Log.d(TAG, flagdbg.toString());
 
-        if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-            if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-                mIconController.hideSystemIconArea(animate);
-            } else {
-                mIconController.showSystemIconArea(animate);
-            }
-        }
-
-        if ((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) {
-            boolean visible = (state1 & StatusBarManager.DISABLE_CLOCK) == 0;
-            mIconController.setClockVisibilityByPolicy(visible);
-        }
         if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
                 animateCollapsePanels();
             }
         }
 
-        if ((diff1 & (StatusBarManager.DISABLE_HOME
-                        | StatusBarManager.DISABLE_RECENT
-                        | StatusBarManager.DISABLE_BACK
-                        | StatusBarManager.DISABLE_SEARCH)) != 0) {
+        if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
             if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
                 // close recents if it's visible
                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
@@ -2518,14 +2493,6 @@
             }
         }
 
-        if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                mIconController.hideNotificationIconArea(animate);
-            } else {
-                mIconController.showNotificationIconArea(animate);
-            }
-        }
-
         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
             mDisableNotificationAlerts =
                     (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
@@ -2739,10 +2706,6 @@
         mFalsingManager.onScreenOff();
     }
 
-    public NotificationShelf getNotificationShelf() {
-        return mNotificationShelf;
-    }
-
     public NotificationStackScrollLayout getNotificationScrollLayout() {
         return mStackScroller;
     }
@@ -2756,6 +2719,14 @@
         updateNotifications();
     }
 
+    public boolean isLaunchTransitionFadingAway() {
+        return mLaunchTransitionFadingAway;
+    }
+
+    public boolean shouldHideNotificationIcons() {
+        return mNotificationPanel.shouldHideNotificationIcons();
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -3071,24 +3042,6 @@
     }
 
     @Override // CommandQueue
-    public void buzzBeepBlinked() {
-    }
-
-    @Override
-    public void notificationLightOff() {
-        if (mDozeServiceHost != null) {
-            mDozeServiceHost.fireNotificationLight(false);
-        }
-    }
-
-    @Override
-    public void notificationLightPulse(int argb, int onMillis, int offMillis) {
-        if (mDozeServiceHost != null) {
-            mDozeServiceHost.fireNotificationLight(true);
-        }
-    }
-
-    @Override // CommandQueue
     public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
             int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
         final int oldVal = mSystemUiVisibility;
@@ -3179,7 +3132,8 @@
 
     void checkBarModes() {
         if (mDemoMode) return;
-        checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions());
+        if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
+                getStatusBarTransitions());
         if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
         mNoAnimationOnNextBarModeChange = false;
     }
@@ -3200,7 +3154,9 @@
     }
 
     private void finishBarAnimations() {
-        mStatusBarView.getBarTransitions().finishAnimations();
+        if (mStatusBarView != null) {
+            mStatusBarView.getBarTransitions().finishAnimations();
+        }
         if (mNavigationBar != null) {
             mNavigationBar.finishBarAnimations();
         }
@@ -3380,8 +3336,6 @@
                 mNotificationData.dump(pw, "  ");
             }
 
-            mIconController.dump(pw);
-
             if (false) {
                 pw.println("see the logcat for a dump of the views we have created.");
                 // must happen on ui thread
@@ -3402,9 +3356,6 @@
             pw.print("  status bar gestures: ");
             mGestureRec.dump(fd, pw, args);
         }
-        if (mStatusBarWindowManager != null) {
-            mStatusBarWindowManager.dump(fd, pw, args);
-        }
 
         if (mHeadsUpManager != null) {
             mHeadsUpManager.dump(fd, pw, args);
@@ -3416,6 +3367,9 @@
         } else {
             pw.println("  mGroupManager: null");
         }
+
+        mLightBarController.dump(fd, pw, args);
+
         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
         }
@@ -3440,9 +3394,8 @@
 
     private void addStatusBarWindow() {
         makeStatusBarView();
-        mStatusBarWindowManager = new StatusBarWindowManager(mContext);
-        mRemoteInputController = new RemoteInputController(mStatusBarWindowManager,
-                mHeadsUpManager);
+        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
+        mRemoteInputController = new RemoteInputController(mHeadsUpManager);
         mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
     }
 
@@ -3635,15 +3588,6 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         updateResources();
         updateDisplaySize(); // populates mDisplayMetrics
-        // Begin old BaseStatusBar.onConfigurationChanged
-        final float fontScale = newConfig.fontScale;
-        final int density = newConfig.densityDpi;
-        if (density != mDensity || mFontScale != fontScale) {
-            onDensityOrFontScaleChanged();
-            mDensity = density;
-            mFontScale = fontScale;
-        }
-        // End old BaseStatusBar.onConfigurationChanged
 
         if (DEBUG) {
             Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
@@ -3964,17 +3908,12 @@
         mContext.unregisterReceiver(mDemoReceiver);
         mAssistManager.destroy();
 
-        final SignalClusterView signalCluster =
-                (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
-        final SignalClusterView signalClusterKeyguard =
-                (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
-        final SignalClusterView signalClusterQs =
-                (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
         if (mQSPanel != null && mQSPanel.getHost() != null) {
             mQSPanel.getHost().destroy();
         }
         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
         mDeviceProvisionedController.removeCallback(mUserSetupObserver);
+        Dependency.get(ConfigurationController.class).removeCallback(mDensityChangeListener);
     }
 
     private boolean mDemoModeAllowed;
@@ -4007,7 +3946,7 @@
             mBatteryController.dispatchDemoCommand(command, args);
         }
         if (modeChange || command.equals(COMMAND_STATUS)) {
-            mIconController.dispatchDemoCommand(command, args);
+            ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args);
         }
         if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
             mNetworkController.dispatchDemoCommand(command, args);
@@ -4150,14 +4089,8 @@
                                 onLaunchTransitionFadingEnded();
                             }
                         });
-                mIconController.getTransitionsController().appTransitionStarting(
-                        SystemClock.uptimeMillis(),
-                        LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
-                if (mNavigationBar != null) {
-                    mNavigationBar.doAppTransitionStarting(
-                            SystemClock.uptimeMillis(),
-                            LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
-                }
+                mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
+                        LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
             }
         };
         if (mNotificationPanel.isLaunchTransitionRunning()) {
@@ -4282,11 +4215,8 @@
         // Treat Keyguard exit animation as an app transition to achieve nice transition for status
         // bar.
         mKeyguardGoingAway = true;
-        mIconController.getTransitionsController().appTransitionPending();
-        if (mNavigationBar != null) {
-            mNavigationBar.setKeyguardGoingAway(true);
-            mNavigationBar.appTransitionPending();
-        }
+        mKeyguardMonitor.notifyKeyguardGoingAway(true);
+        mCommandQueue.appTransitionPending(true);
     }
 
     /**
@@ -4301,16 +4231,14 @@
         mKeyguardFadingAwayDelay = delay;
         mKeyguardFadingAwayDuration = fadeoutDuration;
         mWaitingForKeyguardExit = false;
-        mIconController.getTransitionsController().appTransitionStarting(
-                startTime + fadeoutDuration
+        mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
-                LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
+                LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
         recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
-        if (mNavigationBar != null) {
-            mNavigationBar.doAppTransitionStarting(
+        mCommandQueue.appTransitionStarting(
                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
-                    LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
-        }
+                    LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
+        mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
     }
 
     public boolean isKeyguardFadingAway() {
@@ -4323,9 +4251,7 @@
     public void finishKeyguardFadingAway() {
         mKeyguardFadingAway = false;
         mKeyguardGoingAway = false;
-        if (mNavigationBar != null) {
-            mNavigationBar.setKeyguardGoingAway(false);
-        }
+        mKeyguardMonitor.notifyKeyguardDoneFading();
     }
 
     public void stopWaitingForKeyguardExit() {
@@ -4375,7 +4301,6 @@
         } else {
             mScrimController.setKeyguardShowing(false);
         }
-        mIconPolicy.notifyKeyguardShowingChanged();
         mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
         updateDozingState();
         updatePublicMode();
@@ -4963,33 +4888,11 @@
     }
 
     @Override
-    public void appTransitionPending() {
-        // Use own timings when Keyguard is going away, see keyguardGoingAway and
-        // setKeyguardFadingAway
-        if (!mKeyguardFadingAway) {
-            mIconController.getTransitionsController().appTransitionPending();
-        }
-    }
-
-    @Override
     public void appTransitionCancelled() {
-        mIconController.getTransitionsController().appTransitionCancelled();
         EventBus.getDefault().send(new AppTransitionFinishedEvent());
     }
 
     @Override
-    public void appTransitionStarting(long startTime, long duration) {
-        // Use own timings when Keyguard is going away, see keyguardGoingAway and
-        // setKeyguardFadingAway.
-        if (!mKeyguardGoingAway) {
-            mIconController.getTransitionsController().appTransitionStarting(startTime, duration);
-        }
-        if (mIconPolicy != null) {
-            mIconPolicy.appTransitionStarting(startTime, duration);
-        }
-    }
-
-    @Override
     public void appTransitionFinished() {
         EventBus.getDefault().send(new AppTransitionFinishedEvent());
     }
@@ -5056,44 +4959,9 @@
         return mStatusBarKeyguardViewManager.isShowing();
     }
 
-    private final class ShadeUpdates {
-        private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
-        private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
-
-        public void check() {
-            mNewVisibleNotifications.clear();
-            ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
-            for (int i = 0; i < activeNotifications.size(); i++) {
-                final Entry entry = activeNotifications.get(i);
-                final boolean visible = entry.row != null
-                        && entry.row.getVisibility() == View.VISIBLE;
-                if (visible) {
-                    mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime());
-                }
-            }
-            final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications);
-            mVisibleNotifications.clear();
-            mVisibleNotifications.addAll(mNewVisibleNotifications);
-
-            // We have new notifications
-            if (updates && mDozeServiceHost != null) {
-                mDozeServiceHost.fireNewNotifications();
-            }
-        }
-    }
-
     private final class DozeServiceHost implements DozeHost {
-        // Amount of time to allow to update the time shown on the screen before releasing
-        // the wakelock.  This timeout is design to compensate for the fact that we don't
-        // currently have a way to know when time display contents have actually been
-        // refreshed once we've finished rendering a new frame.
-        private static final long PROCESSING_TIME = 500;
-
         private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
 
-        // Keeps the last reported state by fireNotificationLight.
-        private boolean mNotificationLightOn;
-
         @Override
         public String toString() {
             return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
@@ -5111,19 +4979,6 @@
             }
         }
 
-        public void fireNotificationLight(boolean on) {
-            mNotificationLightOn = on;
-            for (Callback callback : mCallbacks) {
-                callback.onNotificationLight(on);
-            }
-        }
-
-        public void fireNewNotifications() {
-            for (Callback callback : mCallbacks) {
-                callback.onNewNotifications();
-            }
-        }
-
         @Override
         public void addCallback(@NonNull Callback callback) {
             mCallbacks.add(callback);
@@ -5189,11 +5044,6 @@
         }
 
         @Override
-        public boolean isNotificationLightOn() {
-            return mNotificationLightOn;
-        }
-
-        @Override
         public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
             StatusBar.this.startPendingIntentDismissingKeyguard(intent);
         }
@@ -5251,7 +5101,6 @@
     private boolean mVisibleToUser;
 
     private Locale mLocale;
-    private float mFontScale;
 
     protected boolean mUseHeadsUp = false;
     protected boolean mHeadsUpTicker = false;
@@ -5268,7 +5117,6 @@
     private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
 
     private UserManager mUserManager;
-    private int mDensity;
 
     protected KeyguardManager mKeyguardManager;
     private LockPatternUtils mLockPatternUtils;
@@ -5860,10 +5708,12 @@
     }
 
     // The (i) button in the guts that links to the system notification settings for that app
-    private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
+    private void startAppNotificationSettingsActivity(String packageName, final int appUid,
+            final String channelId) {
         final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
         intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
         intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+        intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channelId);
         startNotificationGutsIntent(intent, appUid);
     }
 
@@ -5928,7 +5778,7 @@
                     int appUid) -> {
                 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
                 guts.resetFalsingCheck();
-                startAppNotificationSettingsActivity(pkg, appUid);
+                startAppNotificationSettingsActivity(pkg, appUid, channel.getId());
             };
             final View.OnClickListener onDoneClick = (View v) -> {
                 // If the user has security enabled, show challenge if the setting is changed.
@@ -6748,6 +6598,7 @@
             return null;
         }
         updateNotifications();
+        Dependency.get(LeakDetector.class).trackGarbage(entry);
         return entry.notification;
     }
 
@@ -6756,6 +6607,7 @@
             Log.d(TAG, "createNotificationViews(notification=" + sbn);
         }
         NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        Dependency.get(LeakDetector.class).trackInstance(entry);
         try {
             entry.createIcons(mContext, sbn);
         } catch (NotificationData.IconException exception) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 41f8a91..c339da7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -1,502 +1,48 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
  */
 
 package com.android.systemui.statusbar.phone;
 
-import android.animation.ArgbEvaluator;
 import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
-import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.TextView;
+
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.BatteryMeterView;
 import com.android.systemui.Dependency;
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
-import com.android.systemui.statusbar.NotificationData;
-import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 
-import java.io.PrintWriter;
-import java.util.ArrayList;
+public interface StatusBarIconController {
 
-/**
- * Controls everything regarding the icons in the status bar and on Keyguard, including, but not
- * limited to: notification icons, signal cluster, additional status icons, and clock in the status
- * bar.
- */
-public class StatusBarIconController extends StatusBarIconList implements Tunable {
+    public void addIconGroup(IconManager iconManager);
+    public void removeIconGroup(IconManager iconManager);
+    public void setExternalIcon(String slot);
+    public void setIcon(String slot, int resourceId, CharSequence contentDescription);
+    public void setIcon(String slot, StatusBarIcon icon);
+    public void setIconVisibility(String slotTty, boolean b);
+    public void removeIcon(String slot);
 
     public static final String ICON_BLACKLIST = "icon_blacklist";
-    public static final int DEFAULT_ICON_TINT = Color.WHITE;
-
-    private Context mContext;
-    private StatusBar mStatusBar;
-    private DemoStatusIcons mDemoStatusIcons;
-
-    private LinearLayout mSystemIconArea;
-    private LinearLayout mStatusIcons;
-    private SignalClusterView mSignalCluster;
-    private LinearLayout mStatusIconsKeyguard;
-
-    private NotificationIconAreaController mNotificationIconAreaController;
-    private View mNotificationIconAreaInner;
-    private NotificationShelf mNotificationShelf;
-
-    private BatteryMeterView mBatteryMeterView;
-    private BatteryMeterView mBatteryMeterViewKeyguard;
-    private TextView mClock;
-
-    private int mIconSize;
-    private int mIconHPadding;
-
-    private int mIconTint = DEFAULT_ICON_TINT;
-    private float mDarkIntensity;
-    private final Rect mTintArea = new Rect();
-    private static final Rect sTmpRect = new Rect();
-    private static final int[] sTmpInt2 = new int[2];
-
-    private int mDarkModeIconColorSingleTone;
-    private int mLightModeIconColorSingleTone;
-
-    private final LightBarTransitionsController mTransitionsController;
-
-    private boolean mClockVisibleByPolicy = true;
-    private boolean mClockVisibleByUser = true;
-
-    private final ArraySet<String> mIconBlacklist = new ArraySet<>();
-
-    public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar,
-            StatusBar phoneStatusBar) {
-        super(context.getResources().getStringArray(
-                com.android.internal.R.array.config_statusBarIcons));
-        mContext = context;
-        mStatusBar = phoneStatusBar;
-        mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area);
-        mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
-        mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
-
-        mNotificationShelf = phoneStatusBar.getNotificationShelf();
-        mNotificationIconAreaController = SystemUIFactory.getInstance()
-                .createNotificationIconAreaController(context, phoneStatusBar);
-        mNotificationIconAreaInner =
-                mNotificationIconAreaController.getNotificationInnerAreaView();
-
-        ViewGroup notificationIconArea =
-                (ViewGroup) statusBar.findViewById(R.id.notification_icon_area);
-        notificationIconArea.addView(mNotificationIconAreaInner);
-
-        mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons);
-
-        mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery);
-        mBatteryMeterViewKeyguard = (BatteryMeterView) keyguardStatusBar.findViewById(R.id.battery);
-        scaleBatteryMeterViews(context);
-
-        mClock = (TextView) statusBar.findViewById(R.id.clock);
-        mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
-        mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
-        loadDimens();
-
-        Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
-
-        mTransitionsController = new LightBarTransitionsController(this::setIconTintInternal);
-    }
-
-    public void setSignalCluster(SignalClusterView signalCluster) {
-        mSignalCluster = signalCluster;
-    }
-
-    public LightBarTransitionsController getTransitionsController() {
-        return mTransitionsController;
-    }
-
-    /**
-     * Looks up the scale factor for status bar icons and scales the battery view by that amount.
-     */
-    private void scaleBatteryMeterViews(Context context) {
-        Resources res = context.getResources();
-        TypedValue typedValue = new TypedValue();
-
-        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
-        float iconScaleFactor = typedValue.getFloat();
-
-        int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
-        int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
-        int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
-
-        LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
-                (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
-        scaledLayoutParams.setMarginsRelative(0, 0, 0, marginBottom);
-
-        mBatteryMeterView.setLayoutParams(scaledLayoutParams);
-        mBatteryMeterViewKeyguard.setLayoutParams(scaledLayoutParams);
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (!ICON_BLACKLIST.equals(key)) {
-            return;
-        }
-        mIconBlacklist.clear();
-        mIconBlacklist.addAll(getIconBlacklist(newValue));
-        ArrayList<StatusBarIconView> views = new ArrayList<StatusBarIconView>();
-        // Get all the current views.
-        for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
-            views.add((StatusBarIconView) mStatusIcons.getChildAt(i));
-        }
-        // Remove all the icons.
-        for (int i = views.size() - 1; i >= 0; i--) {
-            removeIcon(views.get(i).getSlot());
-        }
-        // Add them all back
-        for (int i = 0; i < views.size(); i++) {
-            setIcon(views.get(i).getSlot(), views.get(i).getStatusBarIcon());
-        }
-
-        setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(newValue)
-                .contains("clock"));
-        updateClockVisibility();
-    }
-    private void loadDimens() {
-        mIconSize = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.status_bar_icon_size);
-        mIconHPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.status_bar_icon_padding);
-    }
-
-    private void addSystemIcon(int index, StatusBarIcon icon) {
-        String slot = getSlot(index);
-        int viewIndex = getViewIndex(index);
-        boolean blocked = mIconBlacklist.contains(slot);
-        StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked);
-        view.set(icon);
-
-        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
-        lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
-        mStatusIcons.addView(view, viewIndex, lp);
-
-        view = new StatusBarIconView(mContext, slot, null, blocked);
-        view.set(icon);
-        mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
-        applyIconTint();
-    }
-
-    public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
-        int index = getSlotIndex(slot);
-        StatusBarIcon icon = getIcon(index);
-        if (icon == null) {
-            icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
-                    Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription);
-            setIcon(slot, icon);
-        } else {
-            icon.icon = Icon.createWithResource(mContext, resourceId);
-            icon.contentDescription = contentDescription;
-            handleSet(index, icon);
-        }
-    }
-
-    public void setExternalIcon(String slot) {
-        int viewIndex = getViewIndex(getSlotIndex(slot));
-        int height = mContext.getResources().getDimensionPixelSize(
-                R.dimen.status_bar_icon_drawing_size);
-        ImageView imageView = (ImageView) mStatusIcons.getChildAt(viewIndex);
-        imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
-        imageView.setAdjustViewBounds(true);
-        setHeightAndCenter(imageView, height);
-        imageView = (ImageView) mStatusIconsKeyguard.getChildAt(viewIndex);
-        imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
-        imageView.setAdjustViewBounds(true);
-        setHeightAndCenter(imageView, height);
-    }
-
-    private void setHeightAndCenter(ImageView imageView, int height) {
-        ViewGroup.LayoutParams params = imageView.getLayoutParams();
-        params.height = height;
-        if (params instanceof LinearLayout.LayoutParams) {
-            ((LinearLayout.LayoutParams) params).gravity = Gravity.CENTER_VERTICAL;
-        }
-        imageView.setLayoutParams(params);
-    }
-
-    public void setIcon(String slot, StatusBarIcon icon) {
-        setIcon(getSlotIndex(slot), icon);
-    }
-
-    public void removeIcon(String slot) {
-        int index = getSlotIndex(slot);
-        removeIcon(index);
-    }
-
-    public void setIconVisibility(String slot, boolean visibility) {
-        int index = getSlotIndex(slot);
-        StatusBarIcon icon = getIcon(index);
-        if (icon == null || icon.visible == visibility) {
-            return;
-        }
-        icon.visible = visibility;
-        handleSet(index, icon);
-    }
-
-    @Override
-    public void removeIcon(int index) {
-        if (getIcon(index) == null) {
-            return;
-        }
-        super.removeIcon(index);
-        int viewIndex = getViewIndex(index);
-        mStatusIcons.removeViewAt(viewIndex);
-        mStatusIconsKeyguard.removeViewAt(viewIndex);
-    }
-
-    @Override
-    public void setIcon(int index, StatusBarIcon icon) {
-        if (icon == null) {
-            removeIcon(index);
-            return;
-        }
-        boolean isNew = getIcon(index) == null;
-        super.setIcon(index, icon);
-        if (isNew) {
-            addSystemIcon(index, icon);
-        } else {
-            handleSet(index, icon);
-        }
-    }
-
-    private void handleSet(int index, StatusBarIcon icon) {
-        int viewIndex = getViewIndex(index);
-        StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex);
-        view.set(icon);
-        view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex);
-        view.set(icon);
-        applyIconTint();
-    }
-
-    public void updateNotificationIcons(NotificationData notificationData) {
-        mNotificationIconAreaController.updateNotificationIcons(notificationData);
-    }
-
-    public void hideSystemIconArea(boolean animate) {
-        animateHide(mSystemIconArea, animate);
-    }
-
-    public void showSystemIconArea(boolean animate) {
-        animateShow(mSystemIconArea, animate);
-    }
-
-    public void hideNotificationIconArea(boolean animate) {
-        animateHide(mNotificationIconAreaInner, animate);
-    }
-
-    public void showNotificationIconArea(boolean animate) {
-        animateShow(mNotificationIconAreaInner, animate);
-    }
-
-    public void setClockVisibleByUser(boolean visible) {
-        mClockVisibleByUser = visible;
-        updateClockVisibility();
-    }
-
-    public void setClockVisibilityByPolicy(boolean visible) {
-        mClockVisibleByPolicy = visible;
-        updateClockVisibility();
-    }
-
-    private void updateClockVisibility() {
-        int visibility = (mClockVisibleByPolicy && mClockVisibleByUser)
-                ? View.VISIBLE : View.GONE;
-        mClock.setVisibility(visibility);
-    }
-
-    public void dump(PrintWriter pw) {
-        int N = mStatusIcons.getChildCount();
-        pw.println("  icon views: " + N);
-        for (int i=0; i<N; i++) {
-            StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
-            pw.println("    [" + i + "] icon=" + ic);
-        }
-        super.dump(pw);
-    }
-
-    public void dispatchDemoCommand(String command, Bundle args) {
-        if (mDemoStatusIcons == null) {
-            mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize);
-        }
-        mDemoStatusIcons.dispatchDemoCommand(command, args);
-    }
-
-    /**
-     * Hides a view.
-     */
-    private void animateHide(final View v, boolean animate) {
-        v.animate().cancel();
-        if (!animate) {
-            v.setAlpha(0f);
-            v.setVisibility(View.INVISIBLE);
-            return;
-        }
-        v.animate()
-                .alpha(0f)
-                .setDuration(160)
-                .setStartDelay(0)
-                .setInterpolator(Interpolators.ALPHA_OUT)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        v.setVisibility(View.INVISIBLE);
-                    }
-                });
-    }
-
-    /**
-     * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
-     */
-    private void animateShow(View v, boolean animate) {
-        v.animate().cancel();
-        v.setVisibility(View.VISIBLE);
-        if (!animate) {
-            v.setAlpha(1f);
-            return;
-        }
-        v.animate()
-                .alpha(1f)
-                .setDuration(320)
-                .setInterpolator(Interpolators.ALPHA_IN)
-                .setStartDelay(50)
-
-                // We need to clean up any pending end action from animateHide if we call
-                // both hide and show in the same frame before the animation actually gets started.
-                // cancel() doesn't really remove the end action.
-                .withEndAction(null);
-
-        // Synchronize the motion with the Keyguard fading if necessary.
-        if (mStatusBar.isKeyguardFadingAway()) {
-            v.animate()
-                    .setDuration(mStatusBar.getKeyguardFadingAwayDuration())
-                    .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
-                    .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
-                    .start();
-        }
-    }
-
-    /**
-     * Sets the dark area so {@link #setIconsDark} only affects the icons in the specified area.
-     *
-     * @param darkArea the area in which icons should change it's tint, in logical screen
-     *                 coordinates
-     */
-    public void setIconsDarkArea(Rect darkArea) {
-        if (darkArea == null && mTintArea.isEmpty()) {
-            return;
-        }
-        if (darkArea == null) {
-            mTintArea.setEmpty();
-        } else {
-            mTintArea.set(darkArea);
-        }
-        applyIconTint();
-        mNotificationIconAreaController.setTintArea(darkArea);
-    }
-
-    private void setIconTintInternal(float darkIntensity) {
-        mDarkIntensity = darkIntensity;
-        mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
-                mLightModeIconColorSingleTone, mDarkModeIconColorSingleTone);
-        mNotificationIconAreaController.setIconTint(mIconTint);
-        applyIconTint();
-    }
-
-    /**
-     * @return the tint to apply to {@param view} depending on the desired tint {@param color} and
-     *         the screen {@param tintArea} in which to apply that tint
-     */
-    public static int getTint(Rect tintArea, View view, int color) {
-        if (isInArea(tintArea, view)) {
-            return color;
-        } else {
-            return DEFAULT_ICON_TINT;
-        }
-    }
-
-    /**
-     * @return the dark intensity to apply to {@param view} depending on the desired dark
-     *         {@param intensity} and the screen {@param tintArea} in which to apply that intensity
-     */
-    public static float getDarkIntensity(Rect tintArea, View view, float intensity) {
-        if (isInArea(tintArea, view)) {
-            return intensity;
-        } else {
-            return 0f;
-        }
-    }
-
-    /**
-     * @return true if more than half of the {@param view} area are in {@param area}, false
-     *         otherwise
-     */
-    private static boolean isInArea(Rect area, View view) {
-        if (area.isEmpty()) {
-            return true;
-        }
-        sTmpRect.set(area);
-        view.getLocationOnScreen(sTmpInt2);
-        int left = sTmpInt2[0];
-
-        int intersectStart = Math.max(left, area.left);
-        int intersectEnd = Math.min(left + view.getWidth(), area.right);
-        int intersectAmount = Math.max(0, intersectEnd - intersectStart);
-
-        boolean coversFullStatusBar = area.top <= 0;
-        boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
-        return majorityOfWidth && coversFullStatusBar;
-    }
-
-    private void applyIconTint() {
-        for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
-            StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
-            v.setImageTintList(ColorStateList.valueOf(getTint(mTintArea, v, mIconTint)));
-        }
-        mSignalCluster.setIconTint(mIconTint, mDarkIntensity, mTintArea);
-        mBatteryMeterView.setDarkIntensity(
-                isInArea(mTintArea, mBatteryMeterView) ? mDarkIntensity : 0);
-        mClock.setTextColor(getTint(mTintArea, mClock, mIconTint));
-    }
 
     public static ArraySet<String> getIconBlacklist(String blackListStr) {
-        ArraySet<String> ret = new ArraySet<String>();
+        ArraySet<String> ret = new ArraySet<>();
         if (blackListStr == null) {
             blackListStr = "rotate,headset";
         }
@@ -509,34 +55,110 @@
         return ret;
     }
 
-    public void onDensityOrFontScaleChanged() {
-        loadDimens();
-        mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
-        updateClock();
-        for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
-            View child = mStatusIcons.getChildAt(i);
+
+    /**
+     * Version of ViewGroup that observers state from the DarkIconDispatcher.
+     */
+    public static class DarkIconManager extends IconManager {
+        private final DarkIconDispatcher mDarkIconDispatcher;
+        private int mIconHPadding;
+
+        public DarkIconManager(LinearLayout linearLayout) {
+            super(linearLayout);
+            mIconHPadding = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.status_bar_icon_padding);
+            mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
+        }
+
+        @Override
+        protected void onIconAdded(int index, String slot, boolean blocked, StatusBarIcon icon) {
+            StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked);
             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                     ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
             lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
-            child.setLayoutParams(lp);
+            mGroup.addView(view, index, lp);
+            mDarkIconDispatcher.addDarkReceiver(view);
         }
-        for (int i = 0; i < mStatusIconsKeyguard.getChildCount(); i++) {
-            View child = mStatusIconsKeyguard.getChildAt(i);
-            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                    ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
-            child.setLayoutParams(lp);
+
+        @Override
+        protected void destroy() {
+            for (int i = 0; i < mGroup.getChildCount(); i++) {
+                mDarkIconDispatcher.removeDarkReceiver((ImageView) mGroup.getChildAt(i));
+            }
+            mGroup.removeAllViews();
         }
-        scaleBatteryMeterViews(mContext);
+
+        @Override
+        protected void onRemoveIcon(int viewIndex) {
+            mDarkIconDispatcher.removeDarkReceiver((ImageView) mGroup.getChildAt(viewIndex));
+            super.onRemoveIcon(viewIndex);
+        }
+
+        @Override
+        public void onSetIcon(int viewIndex, StatusBarIcon icon) {
+            super.onSetIcon(viewIndex, icon);
+            mDarkIconDispatcher.applyDark((ImageView) mGroup.getChildAt(viewIndex));
+        }
     }
 
-    private void updateClock() {
-        FontSizeUtils.updateFontSize(mClock, R.dimen.status_bar_clock_size);
-        mClock.setPaddingRelative(
-                mContext.getResources().getDimensionPixelSize(
-                        R.dimen.status_bar_clock_starting_padding),
-                0,
-                mContext.getResources().getDimensionPixelSize(
-                        R.dimen.status_bar_clock_end_padding),
-                0);
+    /**
+     * Turns info from StatusBarIconController into ImageViews in a ViewGroup.
+     */
+    public static class IconManager {
+        protected final ViewGroup mGroup;
+        protected final Context mContext;
+        protected final int mIconSize;
+
+        public IconManager(ViewGroup group) {
+            mGroup = group;
+            mContext = group.getContext();
+            mIconSize = mContext.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.status_bar_icon_size);
+        }
+
+        protected void onIconAdded(int index, String slot, boolean blocked, StatusBarIcon icon) {
+            StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked);
+            view.set(icon);
+            mGroup.addView(view, index, new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
+        }
+
+        protected void destroy() {
+            mGroup.removeAllViews();
+        }
+
+        protected void onIconExternal(int viewIndex, int height) {
+            ImageView imageView = (ImageView) mGroup.getChildAt(viewIndex);
+            imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+            imageView.setAdjustViewBounds(true);
+            setHeightAndCenter(imageView, height);
+        }
+
+        protected void onDensityOrFontScaleChanged() {
+            for (int i = 0; i < mGroup.getChildCount(); i++) {
+                View child = mGroup.getChildAt(i);
+                LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+                child.setLayoutParams(lp);
+            }
+        }
+
+        private void setHeightAndCenter(ImageView imageView, int height) {
+            ViewGroup.LayoutParams params = imageView.getLayoutParams();
+            params.height = height;
+            if (params instanceof LinearLayout.LayoutParams) {
+                ((LinearLayout.LayoutParams) params).gravity = Gravity.CENTER_VERTICAL;
+            }
+            imageView.setLayoutParams(params);
+        }
+
+        protected void onRemoveIcon(int viewIndex) {
+            mGroup.removeViewAt(viewIndex);
+        }
+
+        public void onSetIcon(int viewIndex, StatusBarIcon icon) {
+            StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
+            view.set(icon);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
new file mode 100644
index 0000000..70b92ad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
+import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Receives the callbacks from CommandQueue related to icons and tracks the state of
+ * all the icons. Dispatches this state to any IconManagers that are currently
+ * registered with it.
+ */
+public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable,
+        ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController {
+
+    private final DarkIconDispatcher mDarkIconDispatcher;
+
+    private Context mContext;
+    private DemoStatusIcons mDemoStatusIcons;
+
+    private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
+
+    private final ArraySet<String> mIconBlacklist = new ArraySet<>();
+
+    public StatusBarIconControllerImpl(Context context) {
+        super(context.getResources().getStringArray(
+                com.android.internal.R.array.config_statusBarIcons));
+        Dependency.get(ConfigurationController.class).addCallback(this);
+        mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
+        mContext = context;
+
+        loadDimens();
+
+        SysUiServiceProvider.getComponent(context, CommandQueue.class)
+                .addCallbacks(this);
+        Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
+    }
+
+    @Override
+    public void addIconGroup(IconManager group) {
+        mIconGroups.add(group);
+        for (int i = 0; i < mIcons.size(); i++) {
+            StatusBarIcon icon = mIcons.get(i);
+            if (icon != null) {
+                String slot = mSlots.get(i);
+                boolean blocked = mIconBlacklist.contains(slot);
+                group.onIconAdded(getViewIndex(getSlotIndex(slot)), slot, blocked, icon);
+            }
+        }
+    }
+
+    @Override
+    public void removeIconGroup(IconManager group) {
+        group.destroy();
+        mIconGroups.remove(group);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (!ICON_BLACKLIST.equals(key)) {
+            return;
+        }
+        mIconBlacklist.clear();
+        mIconBlacklist.addAll(StatusBarIconController.getIconBlacklist(newValue));
+        ArrayList<StatusBarIcon> current = new ArrayList<>(mIcons);
+        ArrayList<String> currentSlots = new ArrayList<>(mSlots);
+        // Remove all the icons.
+        for (int i = current.size() - 1; i >= 0; i--) {
+            removeIcon(currentSlots.get(i));
+        }
+        // Add them all back
+        for (int i = 0; i < current.size(); i++) {
+            setIcon(currentSlots.get(i), current.get(i));
+        }
+    }
+
+    private void loadDimens() {
+    }
+
+    private void addSystemIcon(int index, StatusBarIcon icon) {
+        String slot = getSlot(index);
+        int viewIndex = getViewIndex(index);
+        boolean blocked = mIconBlacklist.contains(slot);
+
+        mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, icon));
+    }
+
+    @Override
+    public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
+        int index = getSlotIndex(slot);
+        StatusBarIcon icon = getIcon(index);
+        if (icon == null) {
+            icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
+                    Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription);
+            setIcon(slot, icon);
+        } else {
+            icon.icon = Icon.createWithResource(mContext, resourceId);
+            icon.contentDescription = contentDescription;
+            handleSet(index, icon);
+        }
+    }
+
+    @Override
+    public void setExternalIcon(String slot) {
+        int viewIndex = getViewIndex(getSlotIndex(slot));
+        int height = mContext.getResources().getDimensionPixelSize(
+                R.dimen.status_bar_icon_drawing_size);
+        mIconGroups.forEach(l -> l.onIconExternal(viewIndex, height));
+    }
+
+    @Override
+    public void setIcon(String slot, StatusBarIcon icon) {
+        setIcon(getSlotIndex(slot), icon);
+    }
+
+    @Override
+    public void removeIcon(String slot) {
+        int index = getSlotIndex(slot);
+        removeIcon(index);
+    }
+
+    public void setIconVisibility(String slot, boolean visibility) {
+        int index = getSlotIndex(slot);
+        StatusBarIcon icon = getIcon(index);
+        if (icon == null || icon.visible == visibility) {
+            return;
+        }
+        icon.visible = visibility;
+        handleSet(index, icon);
+    }
+
+    @Override
+    public void removeIcon(int index) {
+        if (getIcon(index) == null) {
+            return;
+        }
+        super.removeIcon(index);
+        int viewIndex = getViewIndex(index);
+        mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
+    }
+
+    @Override
+    public void setIcon(int index, StatusBarIcon icon) {
+        if (icon == null) {
+            removeIcon(index);
+            return;
+        }
+        boolean isNew = getIcon(index) == null;
+        super.setIcon(index, icon);
+        if (isNew) {
+            addSystemIcon(index, icon);
+        } else {
+            handleSet(index, icon);
+        }
+    }
+
+    private void handleSet(int index, StatusBarIcon icon) {
+        int viewIndex = getViewIndex(index);
+        mIconGroups.forEach(l -> l.onSetIcon(viewIndex, icon));
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        // TODO: Dump info about all icon groups?
+        ViewGroup statusIcons = mIconGroups.get(0).mGroup;
+        int N = statusIcons.getChildCount();
+        pw.println("  icon views: " + N);
+        for (int i = 0; i < N; i++) {
+            StatusBarIconView ic = (StatusBarIconView) statusIcons.getChildAt(i);
+            pw.println("    [" + i + "] icon=" + ic);
+        }
+        super.dump(pw);
+    }
+
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (mDemoStatusIcons == null) {
+            // TODO: Rework how we handle demo mode.
+            int iconSize = mContext.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.status_bar_icon_size);
+            mDemoStatusIcons = new DemoStatusIcons((LinearLayout) mIconGroups.get(0).mGroup,
+                    iconSize);
+        }
+        mDemoStatusIcons.dispatchDemoCommand(command, args);
+    }
+
+    @Override
+    public void onDensityOrFontScaleChanged() {
+        loadDimens();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
index 660672d..f600908 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
@@ -22,8 +22,8 @@
 import java.util.ArrayList;
 
 public class StatusBarIconList {
-    private ArrayList<String> mSlots = new ArrayList<>();
-    private ArrayList<StatusBarIcon> mIcons = new ArrayList<>();
+    protected ArrayList<String> mSlots = new ArrayList<>();
+    protected ArrayList<StatusBarIcon> mIcons = new ArrayList<>();
 
     public StatusBarIconList(String[] slots) {
         final int N = slots.length;
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 8d5d890..2a69c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -32,6 +32,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.DejankUtils;
 import com.android.keyguard.LatencyTracker;
+import com.android.systemui.Dependency;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.statusbar.CommandQueue;
@@ -67,6 +68,7 @@
     private static String TAG = "StatusBarKeyguardViewManager";
 
     protected final Context mContext;
+    private final StatusBarWindowManager mStatusBarWindowManager;
 
     protected LockPatternUtils mLockPatternUtils;
     protected ViewMediatorCallback mViewMediatorCallback;
@@ -75,7 +77,6 @@
     private FingerprintUnlockController mFingerprintUnlockController;
 
     private ViewGroup mContainer;
-    private StatusBarWindowManager mStatusBarWindowManager;
 
     private boolean mDeviceInteractive = false;
     private boolean mScreenTurnedOn;
@@ -101,16 +102,16 @@
         mContext = context;
         mViewMediatorCallback = callback;
         mLockPatternUtils = lockPatternUtils;
+        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
     }
 
     public void registerStatusBar(StatusBar statusBar,
-            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
+            ViewGroup container,
             ScrimController scrimController,
             FingerprintUnlockController fingerprintUnlockController,
             DismissCallbackRegistry dismissCallbackRegistry) {
         mStatusBar = statusBar;
         mContainer = container;
-        mStatusBarWindowManager = statusBarWindowManager;
         mScrimController = scrimController;
         mFingerprintUnlockController = fingerprintUnlockController;
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 16999b2..deb0070 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -32,6 +32,7 @@
 import android.view.WindowManager;
 
 import com.android.keyguard.R;
+import com.android.systemui.Dumpable;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
@@ -43,7 +44,7 @@
 /**
  * Encapsulates all logic for the status bar window state management.
  */
-public class StatusBarWindowManager implements RemoteInputController.Callback {
+public class StatusBarWindowManager implements RemoteInputController.Callback, Dumpable {
 
     private static final String TAG = "StatusBarWindowManager";
 
@@ -59,6 +60,7 @@
     private final boolean mKeyguardScreenRotation;
     private final float mScreenBrightnessDoze;
     private final State mCurrentState = new State();
+    private OtherwisedCollapsedListener mListener;
 
     public StatusBarWindowManager(Context context) {
         mContext = context;
@@ -154,6 +156,10 @@
 
     private void applyHeight(State state) {
         boolean expanded = isExpanded(state);
+        if (state.forcePluginOpen) {
+            mListener.setWouldOtherwiseCollapse(expanded);
+            expanded = true;
+        }
         if (expanded) {
             mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
         } else {
@@ -356,6 +362,15 @@
         apply(mCurrentState);
     }
 
+    public void setForcePluginOpen(boolean forcePluginOpen) {
+        mCurrentState.forcePluginOpen = forcePluginOpen;
+        apply(mCurrentState);
+    }
+
+    public void setStateListener(OtherwisedCollapsedListener listener) {
+        mListener = listener;
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("StatusBarWindowManager state:");
         pw.println(mCurrentState);
@@ -388,6 +403,7 @@
         int statusBarState;
 
         boolean remoteInputActive;
+        boolean forcePluginOpen;
 
         private boolean isKeyguardShowingAndNotOccluded() {
             return keyguardShowing && !keyguardOccluded;
@@ -419,4 +435,13 @@
             return result.toString();
         }
     }
+
+    /**
+     * Custom listener to pipe data back to plugins about whether or not the status bar would be
+     * collapsed if not for the plugin.
+     * TODO: Find cleaner way to do this.
+     */
+    public interface OtherwisedCollapsedListener {
+        void setWouldOtherwiseCollapse(boolean otherwiseCollapse);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index ffc0d97..bb0748c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -19,11 +19,14 @@
 import libcore.icu.LocaleData;
 
 import android.app.ActivityManager;
+import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
@@ -35,12 +38,18 @@
 import android.text.style.RelativeSizeSpan;
 import android.util.AttributeSet;
 import android.view.Display;
+import android.view.View;
 import android.widget.TextView;
 
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
+import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -52,10 +61,14 @@
 /**
  * Digital clock for the status bar.
  */
-public class Clock extends TextView implements DemoMode, Tunable {
+public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.Callbacks,
+        DarkReceiver, ConfigurationListener {
 
     public static final String CLOCK_SECONDS = "clock_seconds";
 
+    private boolean mClockVisibleByPolicy = true;
+    private boolean mClockVisibleByUser = true;
+
     private boolean mAttached;
     private Calendar mCalendar;
     private String mClockFormatString;
@@ -110,6 +123,8 @@
                     null, Dependency.get(Dependency.TIME_TICK_HANDLER));
             Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
                     StatusBarIconController.ICON_BLACKLIST);
+            SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+            Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
         }
 
         // NOTE: It's safe to do these after registering the receiver since the receiver always runs
@@ -130,6 +145,9 @@
             getContext().unregisterReceiver(mIntentReceiver);
             mAttached = false;
             Dependency.get(TunerService.class).removeTunable(this);
+            SysUiServiceProvider.getComponent(getContext(), CommandQueue.class)
+                    .removeCallbacks(this);
+            Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
         }
     }
 
@@ -158,6 +176,22 @@
         }
     };
 
+    public void setClockVisibleByUser(boolean visible) {
+        mClockVisibleByUser = visible;
+        updateClockVisibility();
+    }
+
+    public void setClockVisibilityByPolicy(boolean visible) {
+        mClockVisibleByPolicy = visible;
+        updateClockVisibility();
+    }
+
+    private void updateClockVisibility() {
+        int visibility = (mClockVisibleByPolicy && mClockVisibleByUser)
+                ? View.VISIBLE : View.GONE;
+        setVisibility(visibility);
+    }
+
     final void updateClock() {
         if (mDemoMode) return;
         mCalendar.setTimeInMillis(System.currentTimeMillis());
@@ -170,9 +204,38 @@
         if (CLOCK_SECONDS.equals(key)) {
             mShowSeconds = newValue != null && Integer.parseInt(newValue) != 0;
             updateShowSeconds();
+        } else {
+            setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(newValue)
+                    .contains("clock"));
+            updateClockVisibility();
         }
     }
 
+    @Override
+    public void disable(int state1, int state2, boolean animate) {
+        boolean clockVisibleByPolicy = (state1 & StatusBarManager.DISABLE_CLOCK) == 0;
+        if (clockVisibleByPolicy != mClockVisibleByPolicy) {
+            setClockVisibilityByPolicy(clockVisibleByPolicy);
+        }
+    }
+
+    @Override
+    public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+        setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+    }
+
+    @Override
+    public void onDensityOrFontScaleChanged() {
+        FontSizeUtils.updateFontSize(this, R.dimen.status_bar_clock_size);
+        setPaddingRelative(
+                mContext.getResources().getDimensionPixelSize(
+                        R.dimen.status_bar_clock_starting_padding),
+                0,
+                mContext.getResources().getDimensionPixelSize(
+                        R.dimen.status_bar_clock_end_padding),
+                0);
+    }
+
     private void updateShowSeconds() {
         if (mShowSeconds) {
             // Wait until we have a display to start trying to show seconds.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
new file mode 100644
index 0000000..788fda8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.res.Configuration;
+
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+
+/**
+ * Common listener for configuration or subsets of configuration changes (like density or
+ * font scaling), providing easy static dependence on these events.
+ */
+public interface ConfigurationController extends CallbackController<ConfigurationListener> {
+
+    interface ConfigurationListener {
+        default void onConfigChanged(Configuration newConfig) {}
+        default void onDensityOrFontScaleChanged() {}
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
new file mode 100644
index 0000000..58944c6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.systemui.statusbar.phone.LightBarTransitionsController;
+
+public interface DarkIconDispatcher {
+
+    void setIconsDarkArea(Rect r);
+    LightBarTransitionsController getTransitionsController();
+
+    void addDarkReceiver(DarkReceiver receiver);
+    void addDarkReceiver(ImageView imageView);
+
+    // Must have been previously been added through one of the addDarkReceive methods above.
+    void removeDarkReceiver(DarkReceiver object);
+    void removeDarkReceiver(ImageView object);
+
+    // Used to reapply darkness on an object, must have previously been added through
+    // addDarkReceiver.
+    void applyDark(ImageView object);
+
+    int DEFAULT_ICON_TINT = Color.WHITE;
+    Rect sTmpRect = new Rect();
+    int[] sTmpInt2 = new int[2];
+
+    /**
+     * @return the tint to apply to {@param view} depending on the desired tint {@param color} and
+     *         the screen {@param tintArea} in which to apply that tint
+     */
+    static int getTint(Rect tintArea, View view, int color) {
+        if (isInArea(tintArea, view)) {
+            return color;
+        } else {
+            return DEFAULT_ICON_TINT;
+        }
+    }
+
+    /**
+     * @return the dark intensity to apply to {@param view} depending on the desired dark
+     *         {@param intensity} and the screen {@param tintArea} in which to apply that intensity
+     */
+    static float getDarkIntensity(Rect tintArea, View view, float intensity) {
+        if (isInArea(tintArea, view)) {
+            return intensity;
+        } else {
+            return 0f;
+        }
+    }
+
+    /**
+     * @return true if more than half of the {@param view} area are in {@param area}, false
+     *         otherwise
+     */
+    static boolean isInArea(Rect area, View view) {
+        if (area.isEmpty()) {
+            return true;
+        }
+        sTmpRect.set(area);
+        view.getLocationOnScreen(sTmpInt2);
+        int left = sTmpInt2[0];
+
+        int intersectStart = Math.max(left, area.left);
+        int intersectEnd = Math.min(left + view.getWidth(), area.right);
+        int intersectAmount = Math.max(0, intersectEnd - intersectStart);
+
+        boolean coversFullStatusBar = area.top <= 0;
+        boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
+        return majorityOfWidth && coversFullStatusBar;
+    }
+
+    interface DarkReceiver {
+        void onDarkChanged(Rect area, float darkIntensity, int tint);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index de47267..728005d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -21,8 +21,12 @@
     boolean isSecure();
     boolean canSkipBouncer();
     boolean isShowing();
+    boolean isKeyguardFadingAway();
+    boolean isKeyguardGoingAway();
+    long getKeyguardFadingAwayDuration();
+    long getKeyguardFadingAwayDelay();
 
     public interface Callback {
-        void onKeyguardChanged();
+        void onKeyguardShowingChanged();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 769f93f..821e635 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -18,13 +18,10 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
-import android.os.RemoteException;
-import android.view.WindowManagerGlobal;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback;
 
 import java.util.ArrayList;
 
@@ -44,6 +41,10 @@
     private boolean mCanSkipBouncer;
 
     private boolean mListening;
+    private boolean mKeyguardFadingAway;
+    private long mKeyguardFadingAwayDelay;
+    private long mKeyguardFadingAwayDuration;
+    private boolean mKeyguardGoingAway;
 
     public KeyguardMonitorImpl(Context context) {
         mContext = context;
@@ -115,8 +116,42 @@
     }
 
     private void notifyKeyguardChanged() {
-        for (Callback callback : mCallbacks) {
-            callback.onKeyguardChanged();
-        }
+        mCallbacks.forEach(Callback::onKeyguardShowingChanged);
+    }
+
+    public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+        mKeyguardFadingAway = true;
+        mKeyguardFadingAwayDelay = delay;
+        mKeyguardFadingAwayDuration = fadeoutDuration;
+        mCallbacks.forEach(Callback::onKeyguardShowingChanged);
+    }
+
+    public void notifyKeyguardDoneFading() {
+        mKeyguardFadingAway = false;
+        mCallbacks.forEach(Callback::onKeyguardShowingChanged);
+    }
+
+    @Override
+    public boolean isKeyguardFadingAway() {
+        return mKeyguardFadingAway;
+    }
+
+    @Override
+    public boolean isKeyguardGoingAway() {
+        return mKeyguardGoingAway;
+    }
+
+    @Override
+    public long getKeyguardFadingAwayDelay() {
+        return mKeyguardFadingAwayDelay;
+    }
+
+    @Override
+    public long getKeyguardFadingAwayDuration() {
+        return mKeyguardFadingAwayDuration;
+    }
+
+    public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
+        mKeyguardGoingAway = keyguardGoingAway;
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 7a32bf1..6df4a21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -850,7 +850,7 @@
 
     private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
         @Override
-        public void onKeyguardChanged() {
+        public void onKeyguardShowingChanged() {
             notifyAdapters();
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index f195f7a..8777aa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -36,14 +36,14 @@
     int getCurrentUser();
     boolean isVolumeRestricted();
 
-    public static class Callback {
-        public void onZenChanged(int zen) {}
-        public void onConditionsChanged(Condition[] conditions) {}
-        public void onNextAlarmChanged() {}
-        public void onZenAvailableChanged(boolean available) {}
-        public void onEffectsSupressorChanged() {}
-        public void onManualRuleChanged(ZenRule rule) {}
-        public void onConfigChanged(ZenModeConfig config) {}
+    public static interface Callback {
+        default void onZenChanged(int zen) {}
+        default void onConditionsChanged(Condition[] conditions) {}
+        default void onNextAlarmChanged() {}
+        default void onZenAvailableChanged(boolean available) {}
+        default void onEffectsSupressorChanged() {}
+        default void onManualRuleChanged(ZenRule rule) {}
+        default void onConfigChanged(ZenModeConfig config) {}
     }
 
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 6006d5a..11927729 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2766,6 +2766,7 @@
 
     private void updateNotificationAnimationStates() {
         boolean running = mAnimationsEnabled || mPulsing;
+        mShelf.setAnimationsEnabled(running);
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index ab562d1..5d11ef3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -42,104 +42,11 @@
     private IStatusBarService mBarService;
 
     @Override
-    public void setIcon(String slot, StatusBarIcon icon) {
-    }
-
-    @Override
-    public void removeIcon(String slot) {
-    }
-
-    public void removeNotification(String key, RankingMap ranking) {
-    }
-
-    @Override
-    public void disable(int state1, int state2, boolean animate) {
-    }
-
-    @Override
-    public void animateExpandNotificationsPanel() {
-    }
-
-    @Override
-    public void animateCollapsePanels(int flags) {
-    }
-
-    @Override
-    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
-            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
-    }
-
-    @Override
-    public void topAppWindowChanged(boolean visible) {
-    }
-
-    @Override
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
-            boolean showImeSwitcher) {
-    }
-
-    @Override // CommandQueue
-    public void setWindowState(int window, int state) {
-    }
-
-    @Override // CommandQueue
-    public void buzzBeepBlinked() {
-    }
-
-    @Override // CommandQueue
-    public void notificationLightOff() {
-    }
-
-    @Override // CommandQueue
-    public void notificationLightPulse(int argb, int onMillis, int offMillis) {
-    }
-
-    @Override
-    public void animateExpandSettingsPanel(String subPanel) {
-    }
-
-    @Override
-    public void showScreenPinningRequest(int taskId) {
-    }
-
-    @Override
-    public void appTransitionPending() {
-    }
-
-    @Override
-    public void appTransitionCancelled() {
-    }
-
-    @Override
-    public void appTransitionStarting(long startTime, long duration) {
-    }
-
-    @Override
-    public void appTransitionFinished() {
-    }
-
-    @Override
-    public void onCameraLaunchGestureDetected(int source) {
-    }
-
-    @Override
     public void showTvPictureInPictureMenu() {
         PipManager.getInstance().showTvPictureInPictureMenu();
     }
 
     @Override
-    public void addQsTile(ComponentName tile) {
-    }
-
-    @Override
-    public void remQsTile(ComponentName tile) {
-    }
-
-    @Override
-    public void clickTile(ComponentName tile) {
-    }
-
-    @Override
     public void start() {
         putComponent(TvStatusBar.class, this);
         CommandQueue commandQueue = getComponent(CommandQueue.class);
@@ -160,8 +67,4 @@
         }
     }
 
-    @Override
-    public void handleSystemNavigationKey(int arg1) {
-        // Not implemented
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index ca582b3..85be4d7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -38,17 +38,20 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
-import com.android.systemui.BatteryMeterDrawable;
+import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.util.leak.LeakDetector;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Set;
 
 
@@ -65,6 +68,8 @@
     private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
     // Map of settings keys to the listener.
     private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
+    // Set of all tunables, used for leak detection.
+    private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null;
     private final Context mContext;
 
     private ContentResolver mContentResolver;
@@ -149,6 +154,10 @@
             mTunableLookup.put(key, new ArraySet<Tunable>());
         }
         mTunableLookup.get(key).add(tunable);
+        if (LeakDetector.ENABLED) {
+            mTunables.add(tunable);
+            Dependency.get(LeakDetector.class).trackCollection(mTunables, "TunerService.mTunables");
+        }
         Uri uri = Settings.Secure.getUriFor(key);
         if (!mListeningUris.containsKey(uri)) {
             mListeningUris.put(uri, key);
@@ -163,6 +172,9 @@
         for (Set<Tunable> list : mTunableLookup.values()) {
             list.remove(tunable);
         }
+        if (LeakDetector.ENABLED) {
+            mTunables.remove(tunable);
+        }
     }
 
     protected void reregisterAll() {
@@ -200,7 +212,8 @@
     public void clearAll() {
         // A couple special cases.
         Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
-        Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
+        Settings.System.putString(mContentResolver,
+                SHOW_PERCENT_SETTING, null);
         Intent intent = new Intent(DemoMode.ACTION_DEMO);
         intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
         mContext.sendBroadcast(intent);
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/AbstractCollection.java b/packages/SystemUI/src/com/android/systemui/util/leak/AbstractCollection.java
new file mode 100644
index 0000000..1534def
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/AbstractCollection.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+abstract class AbstractCollection<T> implements Collection<T> {
+    @Override
+    public abstract int size();
+
+    @Override
+    public abstract boolean isEmpty();
+
+    @Override
+    public boolean contains(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object[] toArray() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T1> T1[] toArray(T1[] t1s) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean add(T t) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> collection) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends T> collection) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> collection) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> collection) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakDetector.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakDetector.java
new file mode 100644
index 0000000..a0f8659
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakDetector.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.systemui.Dumpable;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Collection;
+
+/**
+ * Detects leaks.
+ */
+public class LeakDetector implements Dumpable {
+
+    public static final boolean ENABLED = Build.IS_DEBUGGABLE;
+
+    private final TrackedCollections mTrackedCollections;
+    private final TrackedGarbage mTrackedGarbage;
+    private final TrackedObjects mTrackedObjects;
+
+    @VisibleForTesting
+    public LeakDetector(TrackedCollections trackedCollections,
+            TrackedGarbage trackedGarbage,
+            TrackedObjects trackedObjects) {
+        mTrackedCollections = trackedCollections;
+        mTrackedGarbage = trackedGarbage;
+        mTrackedObjects = trackedObjects;
+    }
+
+    /**
+     * Tracks an instance that has a high leak risk (i.e. has complex ownership and references
+     * a large amount of memory).
+     *
+     * The LeakDetector will monitor and keep weak references to such instances, dump statistics
+     * about them in a bugreport, and in the future dump the heap if their count starts growing
+     * unreasonably.
+     *
+     * This should be called when the instance is first constructed.
+     */
+    public <T> void trackInstance(T object) {
+        if (mTrackedObjects != null) {
+            mTrackedObjects.track(object);
+        }
+    }
+
+    /**
+     * Tracks a collection that is at risk of leaking large objects, e.g. a collection of
+     * dynamically registered listeners.
+     *
+     * The LeakDetector will monitor and keep weak references to such collections, dump
+     * statistics about them in a bugreport, and in the future dump the heap if their size starts
+     * growing unreasonably.
+     *
+     * This should be called whenever the collection grows.
+     *
+     * @param tag A tag for labeling the collection in a bugreport
+     */
+    public <T> void trackCollection(Collection<T> collection, String tag) {
+        if (mTrackedCollections != null) {
+            mTrackedCollections.track(collection, tag);
+        }
+    }
+
+    /**
+     * Tracks an instance that should become garbage soon.
+     *
+     * The LeakDetector will monitor and keep weak references to such garbage, dump
+     * statistics about them in a bugreport, and in the future dump the heap if it is not
+     * collected reasonably soon.
+     *
+     * This should be called when the last strong reference to the instance is dropped.
+     */
+    public void trackGarbage(Object o) {
+        if (mTrackedGarbage != null) {
+            mTrackedGarbage.track(o);
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor df, PrintWriter w, String[] args) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(w, "  ");
+
+        pw.println("SYSUI LEAK DETECTOR");
+        pw.increaseIndent();
+
+        if (mTrackedCollections != null && mTrackedGarbage != null) {
+            pw.println("TrackedCollections:");
+            pw.increaseIndent();
+            mTrackedCollections.dump(pw, (col) -> !TrackedObjects.isTrackedObject(col));
+            pw.decreaseIndent();
+            pw.println();
+
+            pw.println("TrackedObjects:");
+            pw.increaseIndent();
+            mTrackedCollections.dump(pw, TrackedObjects::isTrackedObject);
+            pw.decreaseIndent();
+            pw.println();
+
+            pw.print("TrackedGarbage:");
+            pw.increaseIndent();
+            mTrackedGarbage.dump(pw);
+            pw.decreaseIndent();
+        } else {
+            pw.println("disabled");
+        }
+        pw.decreaseIndent();
+        pw.println();
+    }
+
+    public static LeakDetector create() {
+        if (ENABLED) {
+            TrackedCollections collections = new TrackedCollections();
+            return new LeakDetector(collections, new TrackedGarbage(collections),
+                    new TrackedObjects(collections));
+        } else {
+            return new LeakDetector(null, null, null);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/TrackedCollections.java b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedCollections.java
new file mode 100644
index 0000000..5577daf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedCollections.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import android.os.SystemClock;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * Tracks the size of collections.
+ */
+public class TrackedCollections {
+    private static final long MILLIS_IN_MINUTE = 60 * 1000;
+    private static final long HALFWAY_DELAY = 30 * MILLIS_IN_MINUTE;
+
+    private final WeakIdentityHashMap<Collection<?>, CollectionState> mCollections
+            = new WeakIdentityHashMap<>();
+
+    /**
+     * @see LeakDetector#trackCollection(Collection, String)
+     */
+    public synchronized void track(Collection<?> collection, String tag) {
+        CollectionState collectionState = mCollections.get(collection);
+        if (collectionState == null) {
+            collectionState = new CollectionState();
+            collectionState.tag = tag;
+            collectionState.startUptime = SystemClock.uptimeMillis();
+            mCollections.put(collection, collectionState);
+        }
+        if (collectionState.halfwayCount == -1
+                && SystemClock.uptimeMillis() - collectionState.startUptime > HALFWAY_DELAY) {
+            collectionState.halfwayCount = collectionState.lastCount;
+        }
+        collectionState.lastCount = collection.size();
+        collectionState.lastUptime = SystemClock.uptimeMillis();
+    }
+
+    private static class CollectionState {
+        String tag;
+        long startUptime;
+        /** The number of elements in the collection at startUptime + HALFWAY_DELAY */
+        int halfwayCount = -1;
+        /** The number of elements in the collection at lastUptime */
+        int lastCount = -1;
+        long lastUptime;
+
+        /**
+         * Dump statistics about the tracked collection:
+         * - the tag
+         * - average elements inserted per hour during
+         *   - the first 30min of its existence
+         *   - after the first 30min
+         *   - overall
+         * - the current size of the collection
+         */
+        void dump(PrintWriter pw) {
+            long now = SystemClock.uptimeMillis();
+
+            pw.format("%s: %.2f (start-30min) / %.2f (30min-now) / %.2f (start-now)"
+                            + " (growth rate in #/hour); %d (current size)",
+                    tag,
+                    ratePerHour(startUptime, 0, startUptime + HALFWAY_DELAY, halfwayCount),
+                    ratePerHour(startUptime + HALFWAY_DELAY, halfwayCount, now, lastCount),
+                    ratePerHour(startUptime, 0, now, lastCount),
+                    lastCount);
+        }
+
+        private float ratePerHour(long uptime1, int count1, long uptime2, int count2) {
+            if (uptime1 >= uptime2 || count1 < 0 || count2 < 0) {
+                return Float.NaN;
+            }
+            return ((float) count2 - count1) / (uptime2 - uptime1) * 60 * MILLIS_IN_MINUTE;
+        }
+    }
+
+    public synchronized void dump(PrintWriter pw, Predicate<Collection<?>> filter) {
+        for (Map.Entry<WeakReference<Collection<?>>, CollectionState> entry
+                : mCollections.entrySet()) {
+            Collection<?> key = entry.getKey().get();
+            if (filter == null || key != null && filter.test(key)) {
+                entry.getValue().dump(pw);
+                pw.println();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/TrackedGarbage.java b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedGarbage.java
new file mode 100644
index 0000000..fd59aee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedGarbage.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import android.os.SystemClock;
+import android.util.ArrayMap;
+
+import java.io.PrintWriter;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * Tracks objects that have been marked as garbage.
+ */
+public class TrackedGarbage {
+
+    /** Duration after which we consider garbage to be old. */
+    private static final long GARBAGE_COLLECTION_DEADLINE_MILLIS = 60000; // 1min
+
+    private final HashSet<LeakReference> mGarbage = new HashSet<>();
+    private final ReferenceQueue<Object> mRefQueue = new ReferenceQueue<>();
+    private final TrackedCollections mTrackedCollections;
+
+    public TrackedGarbage(TrackedCollections trackedCollections) {
+        mTrackedCollections = trackedCollections;
+    }
+
+    /**
+     * @see LeakDetector#trackGarbage(Object)
+     */
+    public synchronized void track(Object o) {
+        cleanUp();
+        mGarbage.add(new LeakReference(o, mRefQueue));
+        mTrackedCollections.track(mGarbage, "Garbage");
+    }
+
+    private void cleanUp() {
+        Reference<?> ref;
+        while ((ref = mRefQueue.poll()) != null) {
+            mGarbage.remove(ref);
+        }
+    }
+
+    /**
+     * A reference to something we consider leaked if it still has strong references.
+     *
+     * Helpful for finding potential leaks in a heapdump: Simply find an instance of
+     * LeakReference, find the object it refers to, then find a strong path to a GC root.
+     */
+    private static class LeakReference extends WeakReference<Object> {
+        private final Class<?> clazz;
+        private final long createdUptimeMillis;
+
+        LeakReference(Object t, ReferenceQueue<Object> queue) {
+            super(t, queue);
+            clazz = t.getClass();
+            createdUptimeMillis = SystemClock.uptimeMillis();
+        }
+    }
+
+    /**
+     * Dump statistics about the garbage.
+     *
+     * For each class, dumps the number of "garbage objects" that have not been collected yet.
+     * A large number of old instances indicates a probable leak.
+     */
+    public synchronized void dump(PrintWriter pw) {
+        cleanUp();
+
+        long now = SystemClock.uptimeMillis();
+
+        ArrayMap<Class<?>, Integer> acc = new ArrayMap<>();
+        ArrayMap<Class<?>, Integer> accOld = new ArrayMap<>();
+        for (LeakReference ref : mGarbage) {
+            acc.put(ref.clazz, acc.getOrDefault(ref.clazz, 0) + 1);
+            if (isOld(ref.createdUptimeMillis, now)) {
+                accOld.put(ref.clazz, accOld.getOrDefault(ref.clazz, 0) + 1);
+            }
+        }
+
+        for (Map.Entry<Class<?>, Integer> entry : acc.entrySet()) {
+            pw.print(entry.getKey().getName());
+            pw.print(": ");
+            pw.print(entry.getValue());
+            pw.print(" total, ");
+            pw.print(accOld.getOrDefault(entry.getKey(), 0));
+            pw.print(" old");
+            pw.println();
+        }
+    }
+
+    private boolean isOld(long createdUptimeMillis, long now) {
+        return createdUptimeMillis + GARBAGE_COLLECTION_DEADLINE_MILLIS < now;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/TrackedObjects.java b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedObjects.java
new file mode 100644
index 0000000..88f8b4c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedObjects.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import java.util.Collection;
+import java.util.WeakHashMap;
+
+/**
+ * Tracks instances of classes.
+ */
+public class TrackedObjects {
+
+    private final TrackedCollections mTrackedCollections;
+    private final WeakHashMap<Class<?>, TrackedClass<?>> mTrackedClasses = new WeakHashMap<>();
+
+    public TrackedObjects(TrackedCollections trackedCollections) {
+        mTrackedCollections = trackedCollections;
+    }
+
+    /**
+     * @see LeakDetector#trackInstance(Object)
+     */
+    public synchronized <T> void track(T object) {
+        Class<?> clazz = object.getClass();
+        @SuppressWarnings("unchecked")
+        TrackedClass<T> trackedClass = (TrackedClass<T>) mTrackedClasses.get(clazz);
+
+        if (trackedClass == null) {
+            trackedClass = new TrackedClass<T>();
+            mTrackedClasses.put(clazz, trackedClass);
+        }
+
+        trackedClass.track(object);
+        mTrackedCollections.track(trackedClass, clazz.getName());
+    }
+
+    public static boolean isTrackedObject(Collection<?> collection) {
+        return collection instanceof TrackedClass;
+    }
+
+    private static class TrackedClass<T> extends AbstractCollection<T> {
+        final WeakIdentityHashMap<T, Void> instances = new WeakIdentityHashMap<>();
+
+        void track(T object) {
+            instances.put(object, null);
+        }
+
+        @Override
+        public int size() {
+            return instances.size();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return instances.isEmpty();
+        }
+
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/WeakIdentityHashMap.java b/packages/SystemUI/src/com/android/systemui/util/leak/WeakIdentityHashMap.java
new file mode 100644
index 0000000..d370ac1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/WeakIdentityHashMap.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Like WeakHashMap, but uses identity instead of equality when comparing keys.
+ */
+public class WeakIdentityHashMap<K,V> {
+
+    private final HashMap<WeakReference<K>,V> mMap = new HashMap<>();
+    private final ReferenceQueue<Object> mRefQueue = new ReferenceQueue<>();
+
+    private void cleanUp() {
+        Reference<?> ref;
+        while ((ref = mRefQueue.poll()) != null) {
+            mMap.remove(ref);
+        }
+    }
+
+    public void put(K key, V value) {
+        cleanUp();
+        mMap.put(new CmpWeakReference<>(key, mRefQueue), value);
+    }
+
+    public V get(K key) {
+        cleanUp();
+        return mMap.get(new CmpWeakReference<>(key));
+    }
+
+    public Collection<V> values() {
+        cleanUp();
+        return mMap.values();
+    }
+
+    public Set<Map.Entry<WeakReference<K>, V>> entrySet() {
+        return mMap.entrySet();
+    }
+
+    public int size() {
+        cleanUp();
+        return mMap.size();
+    }
+
+    public boolean isEmpty() {
+        cleanUp();
+        return mMap.isEmpty();
+    }
+
+    private static class CmpWeakReference<K> extends WeakReference<K> {
+        private final int mHashCode;
+
+        public CmpWeakReference(K key) {
+            super(key);
+            mHashCode = System.identityHashCode(key);
+        }
+
+        public CmpWeakReference(K key, ReferenceQueue<Object> refQueue) {
+            super(key, refQueue);
+            mHashCode = System.identityHashCode(key);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            K k = get();
+            if (k != null && o instanceof CmpWeakReference) {
+                return ((CmpWeakReference) o).get() == k;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return mHashCode;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 6d62435..41b75ff 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -35,6 +35,7 @@
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
+    <uses-permission android:name="android.permission.CONTROL_VPN" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/res/layout/custom_view_dark.xml b/packages/SystemUI/tests/res/layout/custom_view_dark.xml
new file mode 100644
index 0000000..9e460a5
--- /dev/null
+++ b/packages/SystemUI/tests/res/layout/custom_view_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#ff000000"
+    />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
index cb0f7a3..09808d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui;
 
-import static junit.framework.Assert.assertEquals;
 
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyFloat;
@@ -51,24 +50,6 @@
     }
 
     @Test
-    public void testGetIntrinsicSize() {
-        assertEquals(
-                mResources.getDimensionPixelSize(R.dimen.battery_width),
-                mBatteryMeter.getIntrinsicWidth());
-        assertEquals(
-                mResources.getDimensionPixelSize(R.dimen.battery_height),
-                mBatteryMeter.getIntrinsicHeight());
-    }
-
-    @Test
-    public void testDrawNothingBeforeOnBatteryLevelChanged() {
-        final Canvas canvas = mock(Canvas.class);
-        mBatteryMeter.draw(canvas);
-        verify(canvas, never()).drawPath(any(), any());
-        verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
-    }
-
-    @Test
     public void testDrawImageButNoTextIfPluggedIn() {
         mBatteryMeter.onBatteryLevelChanged(0, true, true);
         final Canvas canvas = mock(Canvas.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index fb4b6bd..27955ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -22,19 +22,25 @@
 
 import android.os.Looper;
 
+import com.android.systemui.Dependency.DependencyKey;
 import com.android.systemui.statusbar.policy.FlashlightController;
 
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.PrintWriter;
 
 public class DependencyTest extends SysuiTestCase {
 
+    public static final DependencyKey<Dumpable> DUMPABLE = new DependencyKey<>("dumpable");
+    public static final DependencyKey<ConfigurationChangedReceiver> CONFIGURATION_CHANGED_RECEIVER
+            = new DependencyKey<>("config_changed_receiver");
+
     @Test
     public void testClassDependency() {
         FlashlightController f = mock(FlashlightController.class);
         injectTestDependency(FlashlightController.class, f);
-        assertEquals(f, Dependency.get(FlashlightController.class));
+        Assert.assertEquals(f, Dependency.get(FlashlightController.class));
     }
 
     @Test
@@ -47,8 +53,8 @@
     @Test
     public void testDump() {
         Dumpable d = mock(Dumpable.class);
-        injectTestDependency("test", d);
-        Dependency.get("test");
+        injectTestDependency(DUMPABLE, d);
+        Dependency.get(DUMPABLE);
         mDependency.dump(null, mock(PrintWriter.class), null);
         verify(d).dump(eq(null), any(), eq(null));
     }
@@ -56,8 +62,8 @@
     @Test
     public void testConfigurationChanged() {
         ConfigurationChangedReceiver d = mock(ConfigurationChangedReceiver.class);
-        injectTestDependency("test", d);
-        Dependency.get("test");
+        injectTestDependency(CONFIGURATION_CHANGED_RECEIVER, d);
+        Dependency.get(CONFIGURATION_CHANGED_RECEIVER);
         mDependency.onConfigurationChanged(null);
         verify(d).onConfigurationChanged(eq(null));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
index f8f67bb..1678d92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
@@ -29,6 +29,7 @@
 import android.view.WindowManager.LayoutParams;
 import android.widget.FrameLayout;
 
+import com.android.systemui.utils.TestableLooper;
 import com.android.systemui.utils.ViewUtils;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
@@ -59,12 +60,14 @@
     }
 
     @Before
-    public void setupFragment() throws IllegalAccessException, InstantiationException {
+    public void setupFragment() throws Exception {
         mView = new FrameLayout(mContext);
         mView.setId(VIEW_ID);
-        mHandler = new Handler(Looper.getMainLooper());
-        mFragment = mCls.newInstance();
-        postAndWait(() -> {
+
+        TestableLooper.get(this).runWithLooper(() -> {
+            mHandler = new Handler();
+
+            mFragment = mCls.newInstance();
             mFragments = FragmentController.createController(new HostCallbacks());
             mFragments.attachHost(null);
             mFragments.getFragmentManager().beginTransaction()
@@ -73,30 +76,39 @@
         });
     }
 
+    private String hex(Looper looper) {
+        return Integer.toHexString(System.identityHashCode(looper));
+    }
+
     @After
-    public void tearDown() {
+    public void tearDown() throws Exception {
         if (mFragments != null) {
             // Set mFragments to null to let it know not to destroy.
-            postAndWait(() -> mFragments.dispatchDestroy());
+            TestableLooper.get(this).runWithLooper(() -> mFragments.dispatchDestroy());
         }
     }
 
     @Test
     public void testCreateDestroy() {
-        postAndWait(() -> mFragments.dispatchCreate());
+        mFragments.dispatchCreate();
+        processAllMessages();
         destroyFragments();
     }
 
     @Test
     public void testStartStop() {
-        postAndWait(() -> mFragments.dispatchStart());
-        postAndWait(() -> mFragments.dispatchStop());
+        mFragments.dispatchStart();
+        processAllMessages();
+        mFragments.dispatchStop();
+        processAllMessages();
     }
 
     @Test
     public void testResumePause() {
-        postAndWait(() -> mFragments.dispatchResume());
-        postAndWait(() -> mFragments.dispatchPause());
+        mFragments.dispatchResume();
+        processAllMessages();
+        mFragments.dispatchPause();
+        processAllMessages();
     }
 
     @Test
@@ -105,54 +117,57 @@
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                 LayoutParams.TYPE_SYSTEM_ALERT,
                 0, PixelFormat.TRANSLUCENT);
-        postAndWait(() -> mFragments.dispatchResume());
+        mFragments.dispatchResume();
+        processAllMessages();
         attachFragmentToWindow();
         detachFragmentToWindow();
-        postAndWait(() -> mFragments.dispatchPause());
-    }
-
-    protected void attachFragmentToWindow() {
-        ViewUtils.attachView(mView);
-    }
-
-    protected void detachFragmentToWindow() {
-        ViewUtils.detachView(mView);
+        mFragments.dispatchPause();
+        processAllMessages();
     }
 
     @Test
     public void testRecreate() {
-        postAndWait(() -> mFragments.dispatchResume());
-        postAndWait(() -> {
-            mFragments.dispatchPause();
-            Parcelable p = mFragments.saveAllState();
-            mFragments.dispatchDestroy();
+        mFragments.dispatchResume();
+        processAllMessages();
+        mFragments.dispatchPause();
+        Parcelable p = mFragments.saveAllState();
+        mFragments.dispatchDestroy();
 
-            mFragments = FragmentController.createController(new HostCallbacks());
-            mFragments.attachHost(null);
-            mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
-            mFragments.dispatchResume();
-        });
+        mFragments = FragmentController.createController(new HostCallbacks());
+        mFragments.attachHost(null);
+        mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
+        mFragments.dispatchResume();
+        processAllMessages();
     }
 
     @Test
     public void testMultipleResumes() {
-        postAndWait(() -> mFragments.dispatchResume());
-        postAndWait(() -> mFragments.dispatchStop());
-        postAndWait(() -> mFragments.dispatchResume());
+        mFragments.dispatchResume();
+        processAllMessages();
+        mFragments.dispatchStop();
+        processAllMessages();
+        mFragments.dispatchResume();
+        processAllMessages();
+    }
+
+    protected void attachFragmentToWindow() {
+        ViewUtils.attachView(mView);
+        TestableLooper.get(this).processMessages(1);
+    }
+
+    protected void detachFragmentToWindow() {
+        ViewUtils.detachView(mView);
+        TestableLooper.get(this).processMessages(1);
     }
 
     protected void destroyFragments() {
-        postAndWait(() -> mFragments.dispatchDestroy());
+        mFragments.dispatchDestroy();
+        processAllMessages();
         mFragments = null;
     }
 
-    protected void postAndWait(Runnable r) {
-        mHandler.post(r);
-        waitForFragments();
-    }
-
-    protected void waitForFragments() {
-        waitForIdleSync(mHandler);
+    protected void processAllMessages() {
+        TestableLooper.get(this).processAllMessages();
     }
 
     private View findViewById(int id) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysUIRunner.java b/packages/SystemUI/tests/src/com/android/systemui/SysUIRunner.java
new file mode 100644
index 0000000..1607b70
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysUIRunner.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.support.test.internal.runner.junit4.statement.RunAfters;
+import android.support.test.internal.runner.junit4.statement.RunBefores;
+import android.support.test.internal.runner.junit4.statement.UiThreadStatement;
+
+import com.android.systemui.utils.TestableLooper.LooperStatement;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.internal.runners.statements.FailOnTimeout;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+import java.util.List;
+
+public class SysUIRunner extends BlockJUnit4ClassRunner {
+
+    private final long mTimeout;
+    private final Class<?> mKlass;
+
+    public SysUIRunner(Class<?> klass) throws InitializationError {
+        super(klass);
+        mKlass = klass;
+        // Can't seem to get reference to timeout parameter from here, so set default to 10 mins.
+        mTimeout = 10 * 60 * 1000;
+    }
+
+    @Override
+    protected Statement methodInvoker(FrameworkMethod method, Object test) {
+        return UiThreadStatement.shouldRunOnUiThread(method) ? new UiThreadStatement(
+                methodInvokerInt(method, test), true) : methodInvokerInt(method, test);
+    }
+
+    protected Statement methodInvokerInt(FrameworkMethod method, Object test) {
+        RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
+        if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class);
+        if (annotation != null) {
+            return new LooperStatement(super.methodInvoker(method, test),
+                    annotation.setAsMainLooper(), test);
+        }
+        return super.methodInvoker(method, test);
+    }
+
+    protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
+        List befores = this.getTestClass().getAnnotatedMethods(Before.class);
+        return befores.isEmpty() ? statement : new RunBefores(method, statement,
+                befores, target);
+    }
+
+    protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
+        List afters = this.getTestClass().getAnnotatedMethods(After.class);
+        return afters.isEmpty() ? statement : new RunAfters(method, statement, afters,
+                target);
+    }
+
+    protected Statement withPotentialTimeout(FrameworkMethod method, Object test, Statement next) {
+        long timeout = this.getTimeout(method.getAnnotation(Test.class));
+        if (timeout <= 0L && mTimeout > 0L) {
+            timeout = mTimeout;
+        }
+
+        return timeout <= 0L ? next : new FailOnTimeout(next, timeout);
+    }
+
+    private long getTimeout(Test annotation) {
+        return annotation == null ? 0L : annotation.timeout();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 81a50d9..6c454e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -18,29 +18,35 @@
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.support.test.InstrumentationRegistry;
 import android.util.ArrayMap;
+import android.util.Log;
 
+import com.android.systemui.Dependency.DependencyKey;
 import com.android.systemui.utils.TestableContext;
 import com.android.systemui.utils.leaks.Tracker;
 
 import org.junit.After;
 import org.junit.Before;
 
+import java.lang.Thread.UncaughtExceptionHandler;
+
 /**
  * Base class that does System UI specific setup.
  */
 public abstract class SysuiTestCase {
 
+    private Throwable mException;
     private Handler mHandler;
     protected TestableContext mContext;
     protected TestDependency mDependency;
 
     @Before
     public void SysuiSetup() throws Exception {
+        mException = null;
         System.setProperty("dexmaker.share_classloader", "true");
         mContext = new TestableContext(InstrumentationRegistry.getTargetContext(), this);
         SystemUIFactory.createFromConfig(mContext);
@@ -86,15 +92,15 @@
         return null;
     }
 
-    public void injectMockDependency(Class<?> cls) {
-        mDependency.injectTestDependency(cls.getName(), mock(cls));
+    public <T> void injectMockDependency(Class<T> cls) {
+        injectTestDependency(cls, mock(cls));
     }
 
-    public void injectTestDependency(Class<?> cls, Object obj) {
-        mDependency.injectTestDependency(cls.getName(), obj);
+    public <T> void injectTestDependency(Class<T> cls, T obj) {
+        mDependency.injectTestDependency(cls, obj);
     }
 
-    public void injectTestDependency(String key, Object obj) {
+    public <T> void injectTestDependency(DependencyKey<T> key, T obj) {
         mDependency.injectTestDependency(key, obj);
     }
 
@@ -104,16 +110,20 @@
     }
 
     public static class TestDependency extends Dependency {
-        private final ArrayMap<String, Object> mObjs = new ArrayMap<>();
+        private final ArrayMap<Object, Object> mObjs = new ArrayMap<>();
 
-        private void injectTestDependency(String key, Object obj) {
+        private <T> void injectTestDependency(DependencyKey<T> key, T obj) {
+            mObjs.put(key, obj);
+        }
+
+        private <T> void injectTestDependency(Class<T> key, T obj) {
             mObjs.put(key, obj);
         }
 
         @Override
-        protected <T> T createDependency(String cls) {
-            if (mObjs.containsKey(cls)) return (T) mObjs.get(cls);
-            return super.createDependency(cls);
+        protected <T> T createDependency(Object key) {
+            if (mObjs.containsKey(key)) return (T) mObjs.get(key);
+            return super.createDependency(key);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 29d5a36..e7fa799 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -14,43 +14,37 @@
 
 package com.android.systemui.qs;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
-import android.os.Handler;
 import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
 
 import com.android.systemui.Dependency;
 import com.android.systemui.FragmentTestCase;
 import com.android.systemui.R;
+import com.android.systemui.SysUIRunner;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.utils.leaks.LeakCheckedTest;
+import com.android.systemui.util.LayoutInflaterBuilder;
+import com.android.systemui.utils.TestableLooper;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.ArrayList;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.widget.FrameLayout;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(SysUIRunner.class)
+@RunWithLooper(setAsMainLooper = true)
 public class QSFragmentTest extends FragmentTestCase {
 
     public QSFragmentTest() {
@@ -59,32 +53,38 @@
 
     @Before
     public void addLeakCheckDependencies() {
-        injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
+        mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
+                new LayoutInflaterBuilder(mContext)
+                        .replace("com.android.systemui.statusbar.policy.SplitClockView",
+                                FrameLayout.class)
+                        .replace("TextClock", View.class)
+                        .build());
+
+        injectTestDependency(Dependency.BG_LOOPER, TestableLooper.get(this).getLooper());
         injectMockDependency(UserSwitcherController.class);
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
     }
 
     @Test
     public void testListening() {
+        assertEquals(Looper.myLooper(), Looper.getMainLooper());
         QSFragment qs = (QSFragment) mFragment;
-        postAndWait(() -> mFragments.dispatchResume());
-        QSTileHost host = new QSTileHost(mContext, null,
-                mock(StatusBarIconController.class));
+        mFragments.dispatchResume();
+        processAllMessages();
+        QSTileHost host = new QSTileHost(mContext, null, mock(StatusBarIconController.class));
         qs.setHost(host);
-        Handler h = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
 
         qs.setListening(true);
-        waitForIdleSync(h);
+        processAllMessages();
 
         qs.setListening(false);
-        waitForIdleSync(h);
+        processAllMessages();
 
         // Manually push header through detach so it can handle standard cleanup it does on
         // removed from window.
         ((QuickStatusBarHeader) qs.getView().findViewById(R.id.header)).onDetachedFromWindow();
 
         host.destroy();
-        // Ensure the tuner cleans up its persistent listeners.
-        Dependency.get(TunerService.class).destroy();
+        processAllMessages();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index 5401c30..95190e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -161,4 +161,10 @@
         assertEquals(top1.getValue().intValue(), top2.getValue().intValue());
         assertEquals(bottom1.getValue().intValue(), bottom2.getValue().intValue());
     }
+
+    @Test
+    public void testEmptyHeight() {
+        mTileLayout.measure(mLayoutSizeForOneTile, mLayoutSizeForOneTile);
+        assertEquals(0, mTileLayout.getMeasuredHeight());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 43f8629..930e560 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -41,6 +41,7 @@
         mCommandQueue = new CommandQueue();
         mCallbacks = mock(Callbacks.class);
         mCommandQueue.addCallbacks(mCallbacks);
+        verify(mCallbacks).disable(eq(0), eq(0), eq(false));
     }
 
     @After
@@ -171,27 +172,6 @@
     }
 
     @Test
-    public void testBuzzBeepBlink() {
-        mCommandQueue.buzzBeepBlinked();
-        waitForIdleSync();
-        verify(mCallbacks).buzzBeepBlinked();
-    }
-
-    @Test
-    public void testNotificationLightOff() {
-        mCommandQueue.notificationLightOff();
-        waitForIdleSync();
-        verify(mCallbacks).notificationLightOff();
-    }
-
-    @Test
-    public void testNotificationLightPulse() {
-        mCommandQueue.notificationLightPulse(1, 2, 3);
-        waitForIdleSync();
-        verify(mCallbacks).notificationLightPulse(eq(1), eq(2), eq(3));
-    }
-
-    @Test
     public void testScreenPinRequest() {
         mCommandQueue.showScreenPinningRequest(1);
         waitForIdleSync();
@@ -202,7 +182,7 @@
     public void testAppTransitionPending() {
         mCommandQueue.appTransitionPending();
         waitForIdleSync();
-        verify(mCallbacks).appTransitionPending();
+        verify(mCallbacks).appTransitionPending(eq(false));
     }
 
     @Test
@@ -216,7 +196,7 @@
     public void testAppTransitionStarting() {
         mCommandQueue.appTransitionStarting(1, 2);
         waitForIdleSync();
-        verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L));
+        verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L), eq(false));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
new file mode 100644
index 0000000..d07cea1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationCustomViewWrapperTest {
+
+    private Context mContext;
+    private ExpandableNotificationRow mRow;
+
+    @Before
+    @UiThreadTest
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mRow = new ExpandableNotificationRow(mContext, null);
+    }
+
+    @Test
+    public void testBackgroundPersists() {
+        RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.custom_view_dark);
+        View v = views.apply(mContext, null);
+        NotificationViewWrapper wrap = NotificationCustomViewWrapper.wrap(mContext, v, mRow);
+        wrap.notifyContentUpdated(null, false /* isLowPriority */);
+        Assert.assertTrue(wrap.getCustomBackgroundColor() != 0);
+        views.reapply(mContext, v);
+        wrap.notifyContentUpdated(null, false /* isLowPriority */);
+        Assert.assertTrue(wrap.getCustomBackgroundColor() != 0);
+    }
+
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
index 7141170..72f6ca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
@@ -14,12 +14,18 @@
 
 package com.android.systemui.statusbar;
 
+import com.android.systemui.SysUIRunner;
+import com.android.systemui.utils.TestableLooper;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
 import com.android.systemui.utils.ViewUtils;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@RunWith(SysUIRunner.class)
+@RunWithLooper
 public class NotificationMenuRowTest extends LeakCheckedTest {
 
     @Before
@@ -31,6 +37,8 @@
     public void testAttachDetach() {
         NotificationMenuRow row = new NotificationMenuRow(mContext);
         ViewUtils.attachView(row);
+        TestableLooper.get(this).processAllMessages();
         ViewUtils.detachView(row);
+        TestableLooper.get(this).processAllMessages();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 7d9e073..68f9cb05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,36 +16,74 @@
 
 package com.android.systemui.statusbar;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.graphics.drawable.Icon;
-import android.os.Debug;
 import android.os.UserHandle;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
-
-import static junit.framework.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import org.mockito.ArgumentMatcher;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class StatusBarIconViewTest extends SysuiTestCase {
 
+    @Rule
+    public ExpectedException mThrown = ExpectedException.none();
+
     private StatusBarIconView mIconView;
     private StatusBarIcon mStatusBarIcon = mock(StatusBarIcon.class);
 
+    private PackageManager mPackageManagerSpy;
+    private Context mContext;
+    private Resources mMockResources;
+
     @Before
-    public void setUp() {
-        mIconView = new StatusBarIconView(getContext(), "slot", null);
-        mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, getContext().getPackageName(),
-                Icon.createWithResource(getContext(), R.drawable.ic_android), 0, 0, "");
+    public void setUp() throws Exception {
+        // Set up context such that asking for "mockPackage" resources returns mMockResources.
+        mMockResources = mock(Resources.class);
+        mPackageManagerSpy = spy(getContext().getPackageManager());
+        doReturn(mMockResources).when(mPackageManagerSpy)
+                .getResourcesForApplicationAsUser(eq("mockPackage"), anyInt());
+        doReturn(mMockResources).when(mPackageManagerSpy)
+                .getResourcesForApplication(eq("mockPackage"));
+        doReturn(mMockResources).when(mPackageManagerSpy).getResourcesForApplication(argThat(
+                (ArgumentMatcher<ApplicationInfo>) o -> "mockPackage".equals(o.packageName)));
+        mContext = new ContextWrapper(getContext()) {
+            @Override
+            public PackageManager getPackageManager() {
+                return mPackageManagerSpy;
+            }
+        };
+
+        mIconView = new StatusBarIconView(mContext, "test_slot", null);
+        mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+                Icon.createWithResource(mContext, R.drawable.ic_android), 0, 0, "");
     }
 
     @Test
@@ -55,4 +93,11 @@
         assertNull(mIconView.getTag(R.id.icon_is_grayscale));
     }
 
+    @Test
+    public void testSettingOomingIconDoesNotThrowOom() {
+        when(mMockResources.getDrawable(anyInt(), any())).thenThrow(new OutOfMemoryError("mocked"));
+        mStatusBarIcon.icon = Icon.createWithResource("mockPackage", R.drawable.ic_android);
+
+        assertFalse(mIconView.set(mStatusBarIcon));
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
new file mode 100644
index 0000000..f55115e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.StatusBarManager;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+
+import com.android.systemui.FragmentTestCase;
+import com.android.systemui.R;
+import com.android.systemui.SysUIRunner;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+@RunWith(SysUIRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class CollapsedStatusBarFragmentTest extends FragmentTestCase {
+
+    private NotificationIconAreaController mMockNotificiationAreaController;
+    private View mNotificationAreaInner;
+
+    public CollapsedStatusBarFragmentTest() {
+        super(CollapsedStatusBarFragment.class);
+    }
+
+    @Before
+    public void setup() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+        mContext.putComponent(StatusBar.class, mock(StatusBar.class));
+        mContext.putComponent(TunerService.class, mock(TunerService.class));
+        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+        mMockNotificiationAreaController = mock(NotificationIconAreaController.class);
+        mNotificationAreaInner = mock(View.class);
+        when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+        when(mMockNotificiationAreaController.getNotificationInnerAreaView()).thenReturn(
+                mNotificationAreaInner);
+    }
+
+    @Test
+    public void testDisableNone() throws Exception {
+        mFragments.dispatchResume();
+        processAllMessages();
+
+        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        fragment.initNotificationIconArea(mMockNotificiationAreaController);
+        fragment.disable(0, 0, false);
+
+        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
+                .getVisibility());
+    }
+
+    @Test
+    public void testDisableSystemInfo() throws Exception {
+        mFragments.dispatchResume();
+        processAllMessages();
+
+        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        fragment.initNotificationIconArea(mMockNotificiationAreaController);
+        fragment.disable(StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
+
+        assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
+                .getVisibility());
+
+        fragment.disable(0, 0, false);
+
+        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
+                .getVisibility());
+    }
+
+    @Test
+    public void testDisableNotifications() throws Exception {
+        mFragments.dispatchResume();
+        processAllMessages();
+
+        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        fragment.initNotificationIconArea(mMockNotificiationAreaController);
+        fragment.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+
+        Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE));
+
+        fragment.disable(0, 0, false);
+
+        Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.VISIBLE));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index a9d6df7..1fa9846 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -15,18 +15,27 @@
 package com.android.systemui.statusbar.phone;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.Looper;
+import android.view.Display;
 import android.view.WindowManager;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.FragmentTestCase;
+import com.android.systemui.SysUIRunner;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@RunWith(SysUIRunner.class)
+@RunWithLooper(setAsMainLooper = true)
 public class NavigationBarFragmentTest extends FragmentTestCase {
 
     public NavigationBarFragmentTest() {
@@ -35,20 +44,25 @@
 
     @Before
     public void setup() {
+        injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
         mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         mContext.putComponent(StatusBar.class, mock(StatusBar.class));
         mContext.putComponent(Recents.class, mock(Recents.class));
         mContext.putComponent(Divider.class, mock(Divider.class));
-        mContext.addMockSystemService(Context.WINDOW_SERVICE, mock(WindowManager.class));
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+        WindowManager windowManager = mock(WindowManager.class);
+        Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
+        when(windowManager.getDefaultDisplay()).thenReturn(
+                defaultDisplay);
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, windowManager);
     }
 
     @Test
     public void testHomeLongPress() {
-        mContext.addMockSystemService(Context.WINDOW_SERVICE, mock(WindowManager.class));
         NavigationBarFragment navigationBarFragment = (NavigationBarFragment) mFragment;
 
-        postAndWait(() -> mFragments.dispatchResume());
+        mFragments.dispatchResume();
+        processAllMessages();
         navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 21c7fce..e8eee24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -79,6 +79,12 @@
 
         mMetricsReader = new MetricsReader();
         mMetricsReader.checkpoint(); // clear out old logs
+        try {
+            // pause so that no new events arrive in the rest of this millisecond.
+            Thread.sleep(2);
+        } catch (InterruptedException e) {
+            // pass
+        }
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
new file mode 100644
index 0000000..11722fe
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.util.leak;
+
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.util.leak.ReferenceTestUtils.CollectionWaiter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LeakDetectorTest {
+
+    private LeakDetector mLeakDetector;
+
+    @Before
+    public void setup() {
+        mLeakDetector = LeakDetector.create();
+
+        // Note: Do not try to factor out object / collection waiter creation. The optimizer will
+        // try and cache accesses to fields and thus create a GC root for the duration of the test
+        // method, thus breaking the test.
+    }
+
+    @Test
+    public void trackInstance_doesNotLeakTrackedObject() {
+        Object object = new Object();
+        CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
+
+        mLeakDetector.trackInstance(object);
+        object = null;
+        collectionWaiter.waitForCollection();
+    }
+
+    @Test
+    public void trackCollection_doesNotLeakTrackedObject() {
+        Collection<?> object = new ArrayList<>();
+        CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
+
+        mLeakDetector.trackCollection(object, "tag");
+        object = null;
+        collectionWaiter.waitForCollection();
+    }
+
+    @Test
+    public void trackGarbage_doesNotLeakTrackedObject() {
+        Object object = new Object();
+        CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
+
+        mLeakDetector.trackGarbage(object);
+        object = null;
+        collectionWaiter.waitForCollection();
+    }
+
+    @Test
+    public void testDump() throws Exception {
+        Object o1 = new Object();
+        Object o2 = new Object();
+        Collection<Object> col1 = new ArrayList<>();
+
+        mLeakDetector.trackInstance(o1);
+        mLeakDetector.trackCollection(col1, "tag");
+        mLeakDetector.trackGarbage(o2);
+
+        FileOutputStream fos = new FileOutputStream("/dev/null");
+        mLeakDetector.dump(fos.getFD(), new PrintWriter(fos), new String[0]);
+    }
+
+    @Test
+    public void testDisabled() throws Exception {
+        mLeakDetector = new LeakDetector(null, null, null);
+
+        Object o1 = new Object();
+        Object o2 = new Object();
+        Collection<Object> col1 = new ArrayList<>();
+
+        mLeakDetector.trackInstance(o1);
+        mLeakDetector.trackCollection(col1, "tag");
+        mLeakDetector.trackGarbage(o2);
+
+        FileOutputStream fos = new FileOutputStream("/dev/null");
+        mLeakDetector.dump(fos.getFD(), new PrintWriter(fos), new String[0]);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtils.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtils.java
new file mode 100644
index 0000000..b433e7a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtils.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.util.leak;
+
+import android.os.SystemClock;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+/**
+ * Utilities for writing tests that manipulate weak or other references.
+ */
+public class ReferenceTestUtils {
+
+    /** Returns a runnable that blocks until {@code o} has been collected. */
+    public static CollectionWaiter createCollectionWaiter(Object o) {
+        ReferenceQueue<Object> q = new ReferenceQueue<>();
+        Reference<?> ref = new WeakReference<>(o, q);
+        o = null; // Ensure this variable can't be referenced from the lambda.
+
+        return () -> {
+            Runtime.getRuntime().gc();
+            while (true) {
+                try {
+                    if (q.remove(5_000) == ref) {
+                        return;
+                    } else {
+                        throw new RuntimeException("timeout while waiting for object collection");
+                    }
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        };
+    }
+
+    public static void waitForCondition(Condition p) {
+        long deadline = SystemClock.uptimeMillis() + 5_000;
+        while (!p.apply()) {
+            if (SystemClock.uptimeMillis() > deadline) {
+                throw new RuntimeException("timeout while waiting for condition");
+            }
+            SystemClock.sleep(100);
+        }
+    }
+
+    public interface Condition {
+        boolean apply();
+    }
+
+    public interface CollectionWaiter {
+        void waitForCollection();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
new file mode 100644
index 0000000..9da67b7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.util.leak;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ReferenceTestUtilsTest {
+
+    @Test
+    public void testCollectionWaiter_doesntBlockIndefinitely() {
+        ReferenceTestUtils.createCollectionWaiter(new Object()).waitForCollection();
+    }
+
+    @Test
+    public void testConditionWaiter_doesntBlockIndefinitely() {
+        ReferenceTestUtils.waitForCondition(() -> true);
+    }
+
+    @Test
+    public void testConditionWaiter_waitsUntilConditionIsTrue() {
+        int[] countHolder = new int[]{0};
+
+        ReferenceTestUtils.waitForCondition(() -> {
+            countHolder[0] += 1;
+            return countHolder[0] >= 5;
+        });
+
+        assertEquals(5, countHolder[0]);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
new file mode 100644
index 0000000..fb1c1aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.util.leak;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.util.leak.ReferenceTestUtils.CollectionWaiter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WeakIdentityHashMapTest {
+
+    WeakIdentityHashMap<Object, Object> mMap;
+
+    @Before
+    public void setup() {
+        mMap = new WeakIdentityHashMap<>();
+    }
+
+    @Test
+    public void testUsesIdentity() {
+        String a1 = new String("a");
+        String a2 = new String("a");
+        assertNotSame(a1, a2);
+
+        mMap.put(a1, "value1");
+        mMap.put(a2, "value2");
+
+        assertEquals("value1", mMap.get(a1));
+        assertEquals("value2", mMap.get(a2));
+    }
+
+    @Test
+    public void testWeaklyReferences() {
+        Object object = new Object();
+        CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(object);
+
+        mMap.put(object, "value");
+        object = null;
+
+        // Wait until object has been collected. We'll also need to wait for mMap to become empty,
+        // because our collection waiter may be told about the collection earlier than mMap.
+        collectionWaiter.waitForCollection();
+        ReferenceTestUtils.waitForCondition(mMap::isEmpty);
+
+        assertEquals(0, mMap.size());
+        assertTrue(mMap.isEmpty());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
index 62c007f..c4f1003 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
@@ -30,6 +30,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.ArrayMap;
+import android.view.LayoutInflater;
 
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.utils.leaks.Tracker;
@@ -99,6 +100,9 @@
         if (mMockSystemServices != null && mMockSystemServices.containsKey(name)) {
             return mMockSystemServices.get(name);
         }
+        if (name.equals(LAYOUT_INFLATER_SERVICE)) {
+            return getBaseContext().getSystemService(LayoutInflater.class).cloneInContext(this);
+        }
         return super.getSystemService(name);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
new file mode 100644
index 0000000..d275973
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.util.ArrayMap;
+
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * Creates a looper on the current thread with control over if/when messages are
+ * executed. Warning: This class works through some reflection and may break/need
+ * to be updated from time to time.
+ */
+public class TestableLooper {
+
+    private final Method mNext;
+    private final Method mRecycleUnchecked;
+
+    private Looper mLooper;
+    private MessageQueue mQueue;
+    private boolean mMain;
+    private Object mOriginalMain;
+    private MessageHandler mMessageHandler;
+
+    private int mParsedCount;
+    private Handler mHandler;
+    private Message mEmptyMessage;
+
+    public TestableLooper() throws Exception {
+        this(true);
+    }
+
+    public TestableLooper(boolean setMyLooper) throws Exception {
+        setupQueue(setMyLooper);
+        mNext = mQueue.getClass().getDeclaredMethod("next");
+        mNext.setAccessible(true);
+        mRecycleUnchecked = Message.class.getDeclaredMethod("recycleUnchecked");
+        mRecycleUnchecked.setAccessible(true);
+    }
+
+    public Looper getLooper() {
+        return mLooper;
+    }
+
+    private void clearLooper() throws NoSuchFieldException, IllegalAccessException {
+        Field field = Looper.class.getDeclaredField("sThreadLocal");
+        field.setAccessible(true);
+        ThreadLocal<Looper> sThreadLocal = (ThreadLocal<Looper>) field.get(null);
+        sThreadLocal.set(null);
+    }
+
+    private boolean setForCurrentThread() throws NoSuchFieldException, IllegalAccessException {
+        if (Looper.myLooper() != mLooper) {
+            Field field = Looper.class.getDeclaredField("sThreadLocal");
+            field.setAccessible(true);
+            ThreadLocal<Looper> sThreadLocal = (ThreadLocal<Looper>) field.get(null);
+            sThreadLocal.set(mLooper);
+            return true;
+        }
+        return false;
+    }
+
+    private void setupQueue(boolean setMyLooper) throws Exception {
+        if (setMyLooper) {
+            clearLooper();
+            Looper.prepare();
+            mLooper = Looper.myLooper();
+        } else {
+            Constructor<Looper> constructor = Looper.class.getDeclaredConstructor(
+                    boolean.class);
+            constructor.setAccessible(true);
+            mLooper = constructor.newInstance(true);
+        }
+
+        mQueue = mLooper.getQueue();
+        mHandler = new Handler(mLooper);
+    }
+
+    public void setAsMainLooper() throws NoSuchFieldException, IllegalAccessException {
+        mMain = true;
+        setAsMainInt();
+    }
+
+    private void setAsMainInt() throws NoSuchFieldException, IllegalAccessException {
+        Field field = mLooper.getClass().getDeclaredField("sMainLooper");
+        field.setAccessible(true);
+        if (mOriginalMain == null) {
+            mOriginalMain = field.get(null);
+        }
+        field.set(null, mLooper);
+    }
+
+    /**
+     * Must be called if setAsMainLooper is called to restore the main looper when the
+     * test is complete, otherwise the main looper will not be available for any subsequent
+     * tests.
+     */
+    public void destroy() throws NoSuchFieldException, IllegalAccessException {
+        if (Looper.myLooper() == mLooper) {
+            clearLooper();
+        }
+        if (mMain && mOriginalMain != null) {
+            Field field = mLooper.getClass().getDeclaredField("sMainLooper");
+            field.setAccessible(true);
+            field.set(null, mOriginalMain);
+            mOriginalMain = null;
+        }
+    }
+
+    public void setMessageHandler(MessageHandler handler) {
+        mMessageHandler = handler;
+    }
+
+    /**
+     * Parse num messages from the message queue.
+     *
+     * @param num Number of messages to parse
+     */
+    public int processMessages(int num) {
+        for (int i = 0; i < num; i++) {
+            if (!parseMessageInt()) {
+                return i + 1;
+            }
+        }
+        return num;
+    }
+
+    public void processAllMessages() {
+        while (processQueuedMessages() != 0) ;
+    }
+
+    private int processQueuedMessages() {
+        int count = 0;
+        mEmptyMessage = mHandler.obtainMessage(1);
+        mHandler.sendMessageDelayed(mEmptyMessage, 1);
+        while (parseMessageInt()) count++;
+        return count;
+    }
+
+    private boolean parseMessageInt() {
+        try {
+            Message result = (Message) mNext.invoke(mQueue);
+            if (result != null) {
+                // This is a break message.
+                if (result == mEmptyMessage) {
+                    mRecycleUnchecked.invoke(result);
+                    return false;
+                }
+
+                if (mMessageHandler != null) {
+                    if (mMessageHandler.onMessageHandled(result)) {
+                        result.getTarget().dispatchMessage(result);
+                        mRecycleUnchecked.invoke(result);
+                    } else {
+                        mRecycleUnchecked.invoke(result);
+                        // Message handler indicated it doesn't want us to continue.
+                        return false;
+                    }
+                } else {
+                    result.getTarget().dispatchMessage(result);
+                    mRecycleUnchecked.invoke(result);
+                }
+            } else {
+                // No messages, don't continue parsing
+                return false;
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return true;
+    }
+
+    /**
+     * Runs an executable with myLooper set and processes all messages added.
+     */
+    public void runWithLooper(RunnableWithException runnable) throws Exception {
+        boolean set = setForCurrentThread();
+        runnable.run();
+        processAllMessages();
+        if (set) clearLooper();
+    }
+
+    public interface RunnableWithException {
+        void run() throws Exception;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.TYPE})
+    public @interface RunWithLooper {
+        boolean setAsMainLooper() default false;
+    }
+
+    private static final Map<Object, TestableLooper> sLoopers = new ArrayMap<>();
+
+    public static TestableLooper get(Object test) {
+        return sLoopers.get(test);
+    }
+
+    public static class LooperStatement extends Statement {
+        private final boolean mSetAsMain;
+        private final Statement mBase;
+        private final TestableLooper mLooper;
+
+        public LooperStatement(Statement base, boolean setAsMain, Object test) {
+            mBase = base;
+            try {
+                mLooper = new TestableLooper(false);
+                sLoopers.put(test, mLooper);
+                mSetAsMain = setAsMain;
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public void evaluate() throws Throwable {
+            mLooper.setForCurrentThread();
+            if (mSetAsMain) {
+                mLooper.setAsMainLooper();
+            }
+
+            mBase.evaluate();
+
+            mLooper.destroy();
+        }
+    }
+
+    public interface MessageHandler {
+        /**
+         * Return true to have the message executed and delivered to target.
+         * Return false to not execute the message and stop executing messages.
+         */
+        boolean onMessageHandled(Message m);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooperTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooperTest.java
new file mode 100644
index 0000000..2416e1d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooperTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import com.android.systemui.SysUIRunner;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.TestableLooper.MessageHandler;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(SysUIRunner.class)
+@RunWithLooper
+public class TestableLooperTest extends SysuiTestCase {
+
+    private TestableLooper mTestableLooper;
+
+    @Before
+    public void setup() throws Exception {
+        mTestableLooper = TestableLooper.get(this);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mTestableLooper.destroy();
+    }
+
+    @Test
+    public void testMessageExecuted() throws Exception {
+        Handler h = new Handler();
+        Runnable r = mock(Runnable.class);
+        h.post(r);
+        verify(r, never()).run();
+        mTestableLooper.processAllMessages();
+        verify(r).run();
+    }
+
+    @Test
+    public void testMessageCallback() throws Exception {
+        Handler h = new Handler();
+        Message m = h.obtainMessage(3);
+        Runnable r = mock(Runnable.class);
+        MessageHandler messageHandler = mock(MessageHandler.class);
+        when(messageHandler.onMessageHandled(any())).thenReturn(false);
+        mTestableLooper.setMessageHandler(messageHandler);
+
+        m.sendToTarget();
+        h.post(r);
+
+        mTestableLooper.processAllMessages();
+
+        verify(messageHandler).onMessageHandled(eq(m));
+        // This should never be run becaus the mock returns false on the first message, and
+        // the second will get skipped.
+        verify(r, never()).run();
+    }
+
+    @Test
+    public void testProcessNumberOfMessages() throws Exception {
+        Handler h = new Handler();
+        Runnable r = mock(Runnable.class);
+        h.post(r);
+        h.post(r);
+        h.post(r);
+
+        mTestableLooper.processMessages(2);
+
+        verify(r, times(2)).run();
+    }
+
+    @Test
+    public void testProcessAllMessages() throws Exception {
+        Handler h = new Handler();
+        Runnable r = mock(Runnable.class);
+        Runnable poster = () -> h.post(r);
+        h.post(poster);
+
+        mTestableLooper.processAllMessages();
+        verify(r).run();
+    }
+
+    @Test
+    public void test3Chain() throws Exception {
+        Handler h = new Handler();
+        Runnable r = mock(Runnable.class);
+        Runnable poster = () -> h.post(r);
+        Runnable poster2 = () -> h.post(poster);
+        h.post(poster2);
+
+        mTestableLooper.processAllMessages();
+        verify(r).run();
+    }
+
+    @Test
+    public void testProcessAllMessages_2Messages() throws Exception {
+        Handler h = new Handler();
+        Runnable r = mock(Runnable.class);
+        Runnable r2 = mock(Runnable.class);
+        h.post(r);
+        h.post(r2);
+
+        mTestableLooper.processAllMessages();
+        verify(r).run();
+        verify(r2).run();
+    }
+
+    @Test
+    public void testMainLooper() throws Exception {
+        assertNotEquals(Looper.myLooper(), Looper.getMainLooper());
+
+        Looper originalMain = Looper.getMainLooper();
+        mTestableLooper.setAsMainLooper();
+        assertEquals(Looper.myLooper(), Looper.getMainLooper());
+        Runnable r = mock(Runnable.class);
+
+        new Handler(Looper.getMainLooper()).post(r);
+        mTestableLooper.processAllMessages();
+
+        verify(r).run();
+        mTestableLooper.destroy();
+
+        assertEquals(originalMain, Looper.getMainLooper());
+    }
+
+    @Test
+    public void testNotMyLooper() throws Exception {
+        TestableLooper looper = new TestableLooper(false);
+
+        assertEquals(Looper.myLooper(), mTestableLooper.getLooper());
+        assertNotEquals(Looper.myLooper(), looper.getLooper());
+
+        Runnable r = mock(Runnable.class);
+        Runnable r2 = mock(Runnable.class);
+        new Handler().post(r);
+        new Handler(looper.getLooper()).post(r2);
+
+        looper.processAllMessages();
+        verify(r2).run();
+        verify(r, never()).run();
+
+        mTestableLooper.processAllMessages();
+        verify(r).run();
+    }
+
+    @Test
+    public void testNonMainLooperAnnotation() {
+        assertNotEquals(Looper.myLooper(), Looper.getMainLooper());
+    }
+
+    @Test
+    @RunWithLooper(setAsMainLooper = true)
+    public void testMainLooperAnnotation() {
+        assertEquals(Looper.myLooper(), Looper.getMainLooper());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
index 01996ca..07e5f66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
@@ -29,18 +29,16 @@
     public static void attachView(View view) {
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
-                LayoutParams.TYPE_SYSTEM_ALERT,
+                LayoutParams.TYPE_APPLICATION_OVERLAY,
                 0, PixelFormat.TRANSLUCENT);
         Handler handler = new Handler(Looper.getMainLooper());
         handler.post(() -> InstrumentationRegistry.getContext()
                 .getSystemService(WindowManager.class).addView(view, lp));
-        SysuiTestCase.waitForIdleSync(handler);
     }
 
     public static void detachView(View view) {
         Handler handler = new Handler(Looper.getMainLooper());
         handler.post(() -> InstrumentationRegistry.getContext()
                 .getSystemService(WindowManager.class).removeView(view));
-        SysuiTestCase.waitForIdleSync(handler);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
index 39bbf2d..21871fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
@@ -45,6 +45,26 @@
     }
 
     @Override
+    public boolean isKeyguardFadingAway() {
+        return false;
+    }
+
+    @Override
+    public boolean isKeyguardGoingAway() {
+        return false;
+    }
+
+    @Override
+    public long getKeyguardFadingAwayDuration() {
+        return 0;
+    }
+
+    @Override
+    public long getKeyguardFadingAwayDelay() {
+        return 0;
+    }
+
+    @Override
     public boolean canSkipBouncer() {
         return false;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
new file mode 100644
index 0000000..b13535f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils.leaks;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
+
+public class FakeStatusBarIconController extends BaseLeakChecker<IconManager>
+        implements StatusBarIconController {
+
+    public FakeStatusBarIconController(LeakCheckedTest test) {
+        super(test, "StatusBarGroup");
+    }
+
+    @Override
+    public void addIconGroup(IconManager iconManager) {
+        addCallback(iconManager);
+    }
+
+    @Override
+    public void removeIconGroup(IconManager iconManager) {
+        removeCallback(iconManager);
+    }
+
+    @Override
+    public void setExternalIcon(String slot) {
+
+    }
+
+    @Override
+    public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
+
+    }
+
+    @Override
+    public void setIcon(String slot, StatusBarIcon icon) {
+
+    }
+
+    @Override
+    public void setIconVisibility(String slotTty, boolean b) {
+
+    }
+
+    @Override
+    public void removeIcon(String slot) {
+
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java
index f553277..b841ce9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeTunerService.java
@@ -25,6 +25,7 @@
     public FakeTunerService(Context context, LeakCheckedTest test) {
         super(context);
         mBaseLeakChecker = new BaseLeakChecker<>(test, "tunable");
+        destroy();
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
index c2048c7..6c51524 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
@@ -22,6 +22,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CallbackController;
@@ -75,6 +76,7 @@
             NetworkController.class,
             PluginManager.class,
             TunerService.class,
+            StatusBarIconController.class,
     };
 
     @Rule
@@ -121,6 +123,8 @@
                 obj = new FakePluginManager(mContext, this);
             } else if (cls == TunerService.class) {
                 obj = new FakeTunerService(mContext, this);
+            } else if (cls == StatusBarIconController.class) {
+                obj = new FakeStatusBarIconController(this);
             } else {
                 Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
             }
@@ -145,10 +149,14 @@
 
     public void injectLeakCheckedDependencies(Class<?>... cls) {
         for (Class<?> c : cls) {
-            injectTestDependency(c, getLeakChecker(c));
+            injectLeakCheckedDependency(c);
         }
     }
 
+    public <T> void injectLeakCheckedDependency(Class<T> c) {
+        injectTestDependency(c, getLeakChecker(c));
+    }
+
     public <T extends CallbackController> T addListening(T mock, Class<T> cls, String tag) {
         doAnswer(new Answer<Void>() {
             @Override
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index a590805..e4b53cb 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3388,6 +3388,9 @@
     // OS: O
     FIELD_GESTURE_VELOCITY = 827;
 
+    // OPEN: Carrier demo mode password dialog
+    CARRIER_DEMO_MODE_PASSWORD = 828;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index a861522..aae5dd8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -70,6 +70,8 @@
 import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.hardware.fingerprint.IFingerprintService;
+import android.provider.SettingsStringUtil.ComponentNameSet;
+import android.provider.SettingsStringUtil.SettingStringHelper;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
 import android.util.Slog;
@@ -98,9 +100,9 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.SomeArgs;
 import com.android.server.LocalServices;
-
 import com.android.server.policy.AccessibilityShortcutController;
 import com.android.server.statusbar.StatusBarManagerInternal;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.FileDescriptor;
@@ -445,7 +447,7 @@
                 }
                 return userState.getClientState();
             } else {
-                userState.mClients.register(client);
+                userState.mUserClients.register(client);
                 // If this client is not for the current user we do not
                 // return a state since it is not for the foreground user.
                 // We will send the state to the client on a user switch.
@@ -813,6 +815,42 @@
         }
     }
 
+    /**
+     * Invoked remotely over AIDL by SysUi when the accessibility button within the system's
+     * navigation area has been clicked.
+     */
+    @Override
+    public void notifyAccessibilityButtonClicked() {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Caller does not hold permission "
+                    + android.Manifest.permission.STATUS_BAR);
+        }
+        synchronized (mLock) {
+            notifyAccessibilityButtonClickedLocked();
+        }
+    }
+
+    /**
+     * Invoked remotely over AIDL by SysUi when the availability of the accessibility
+     * button within the system's navigation area has changed.
+     *
+     * @param available {@code true} if the accessibility button is available to the
+     *                  user, {@code false} otherwise
+     */
+    @Override
+    public void notifyAccessibilityButtonAvailabilityChanged(boolean available) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Caller does not hold permission "
+                    + android.Manifest.permission.STATUS_BAR);
+        }
+        synchronized (mLock) {
+            notifyAccessibilityButtonAvailabilityChangedLocked(available);
+        }
+    }
+
+
     boolean onGesture(int gestureId) {
         synchronized (mLock) {
             boolean handled = notifyGestureLocked(gestureId, false);
@@ -927,7 +965,7 @@
             oldUserState.onSwitchToAnotherUser();
 
             // Disable the local managers for the old user.
-            if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
+            if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) {
                 mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
                         oldUserState.mUserId, 0).sendToTarget();
             }
@@ -1044,6 +1082,28 @@
         }
     }
 
+    private void notifyAccessibilityButtonClickedLocked() {
+        final UserState state = getCurrentUserStateLocked();
+        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+            final Service service = state.mBoundServices.get(i);
+            // TODO(b/34720082): Only notify a single user-defined service
+            if (service.mRequestAccessibilityButton) {
+                service.notifyAccessibilityButtonClickedLocked();
+            }
+        }
+    }
+
+    private void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
+        final UserState state = getCurrentUserStateLocked();
+        state.mIsAccessibilityButtonAvailable = available;
+        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+            final Service service = state.mBoundServices.get(i);
+            if (service.mRequestAccessibilityButton) {
+                service.notifyAccessibilityButtonAvailabilityChangedLocked(available);
+            }
+        }
+    }
+
     /**
      * Removes an AccessibilityInteractionConnection.
      *
@@ -1178,7 +1238,7 @@
                 service.onAdded();
                 userState.mBoundServices.add(service);
                 userState.mComponentNameToServiceMap.put(service.mComponentName, service);
-                scheduleNotifyClientsOfServicesStateChange();
+                scheduleNotifyClientsOfServicesStateChange(userState);
             }
         } catch (RemoteException re) {
             /* do nothing */
@@ -1200,7 +1260,7 @@
             Service boundService = userState.mBoundServices.get(i);
             userState.mComponentNameToServiceMap.put(boundService.mComponentName, boundService);
         }
-        scheduleNotifyClientsOfServicesStateChange();
+        scheduleNotifyClientsOfServicesStateChange(userState);
     }
 
     /**
@@ -1362,16 +1422,16 @@
         final int clientState = userState.getClientState();
         if (userState.mLastSentClientState != clientState
                 && (mGlobalClients.getRegisteredCallbackCount() > 0
-                        || userState.mClients.getRegisteredCallbackCount() > 0)) {
+                        || userState.mUserClients.getRegisteredCallbackCount() > 0)) {
             userState.mLastSentClientState = clientState;
             mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
                     clientState, userState.mUserId).sendToTarget();
         }
     }
 
-    private void scheduleNotifyClientsOfServicesStateChange() {
-        mMainHandler.obtainMessage(MainHandler.MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS)
-                .sendToTarget();
+    private void scheduleNotifyClientsOfServicesStateChange(UserState userState) {
+        mMainHandler.obtainMessage(MainHandler.MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS,
+                userState.mUserId).sendToTarget();
     }
 
     private void scheduleUpdateInputFilter(UserState userState) {
@@ -2013,10 +2073,12 @@
      * Enables accessibility service specified by {@param componentName} for the {@param userId}.
      */
     private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
-        SettingsStringHelper settingsHelper = new SettingsStringHelper(
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
-        settingsHelper.addService(componentName);
-        settingsHelper.writeToSettings();
+        final SettingStringHelper setting =
+                new SettingStringHelper(
+                        mContext.getContentResolver(),
+                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                        userId);
+        setting.write(ComponentNameSet.add(setting.read(), componentName));
 
         UserState userState = getUserStateLocked(userId);
         if (userState.mEnabledServices.add(componentName)) {
@@ -2028,10 +2090,12 @@
      * Disables accessibility service specified by {@param componentName} for the {@param userId}.
      */
     private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
-        SettingsStringHelper settingsHelper = new SettingsStringHelper(
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
-        settingsHelper.deleteService(componentName);
-        settingsHelper.writeToSettings();
+        final SettingStringHelper setting =
+                new SettingStringHelper(
+                        mContext.getContentResolver(),
+                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                        userId);
+        setting.write(ComponentNameSet.remove(setting.read(), componentName));
 
         UserState userState = getUserStateLocked(userId);
         if (userState.mEnabledServices.remove(componentName)) {
@@ -2060,45 +2124,6 @@
         return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode);
     }
 
-    private class SettingsStringHelper {
-        private static final String SETTINGS_DELIMITER = ":";
-        private ContentResolver mContentResolver;
-        private final String mSettingsName;
-        private Set<String> mServices;
-        private final int mUserId;
-
-        public SettingsStringHelper(String name, int userId) {
-            mUserId = userId;
-            mSettingsName = name;
-            mContentResolver = mContext.getContentResolver();
-            String servicesString = Settings.Secure.getStringForUser(
-                    mContentResolver, mSettingsName, userId);
-            mServices = new HashSet();
-            if (!TextUtils.isEmpty(servicesString)) {
-                final TextUtils.SimpleStringSplitter colonSplitter =
-                        new TextUtils.SimpleStringSplitter(SETTINGS_DELIMITER.charAt(0));
-                colonSplitter.setString(servicesString);
-                while (colonSplitter.hasNext()) {
-                    final String serviceName = colonSplitter.next();
-                    mServices.add(serviceName);
-                }
-            }
-        }
-
-        public void addService(ComponentName component) {
-            mServices.add(component.flattenToString());
-        }
-
-        public void deleteService(ComponentName component) {
-            mServices.remove(component.flattenToString());
-        }
-
-        public void writeToSettings() {
-            Settings.Secure.putStringForUser(mContentResolver, mSettingsName,
-                    TextUtils.join(SETTINGS_DELIMITER, mServices), mUserId);
-        }
-    }
-
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
@@ -2225,12 +2250,12 @@
                     final int clientState = msg.arg1;
                     final int userId = msg.arg2;
                     sendStateToClients(clientState, mGlobalClients);
-                    sendStateToClientsForUser(clientState, userId);
+                    sendStateToClients(clientState, getUserClientsForId(userId));
                 } break;
 
                 case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
                     final int userId = msg.arg1;
-                    sendStateToClientsForUser(0, userId);
+                    sendStateToClients(0, getUserClientsForId(userId));
                 } break;
 
                 case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: {
@@ -2257,7 +2282,9 @@
                 } break;
 
                 case MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS: {
-                    notifyClientsOfServicesStateChange();
+                    final int userId = msg.arg1;
+                    notifyClientsOfServicesStateChange(mGlobalClients);
+                    notifyClientsOfServicesStateChange(getUserClientsForId(userId));
                 } break;
 
                 case MSG_UPDATE_FINGERPRINT: {
@@ -2282,12 +2309,12 @@
             }
         }
 
-        private void sendStateToClientsForUser(int clientState, int userId) {
+        private RemoteCallbackList<IAccessibilityManagerClient> getUserClientsForId(int userId) {
             final UserState userState;
             synchronized (mLock) {
                 userState = getUserStateLocked(userId);
             }
-            sendStateToClients(clientState, userState.mClients);
+            return userState.mUserClients;
         }
 
         private void sendStateToClients(int clientState,
@@ -2307,11 +2334,8 @@
             }
         }
 
-        private void notifyClientsOfServicesStateChange() {
-            RemoteCallbackList<IAccessibilityManagerClient> clients;
-            synchronized (mLock) {
-                clients = getCurrentUserStateLocked().mClients;
-            }
+        private void notifyClientsOfServicesStateChange(
+                RemoteCallbackList<IAccessibilityManagerClient> clients) {
             try {
                 final int userClientCount = clients.beginBroadcast();
                 for (int i = 0; i < userClientCount; i++) {
@@ -2426,6 +2450,8 @@
 
         boolean mCaptureFingerprintGestures;
 
+        boolean mRequestAccessibilityButton;
+
         int mFetchFlags;
 
         long mNotificationTimeout;
@@ -2581,6 +2607,8 @@
                     & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
             mCaptureFingerprintGestures = (info.flags
                     & AccessibilityServiceInfo.FLAG_CAPTURE_FINGERPRINT_GESTURES) != 0;
+            mRequestAccessibilityButton = (info.flags
+                    & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
         }
 
         /**
@@ -2694,7 +2722,7 @@
                     }
                     UserState userState = getUserStateLocked(mUserId);
                     onUserStateChangedLocked(userState);
-                    scheduleNotifyClientsOfServicesStateChange();
+                    scheduleNotifyClientsOfServicesStateChange(userState);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -2904,7 +2932,7 @@
         public boolean findAccessibilityNodeInfoByAccessibilityId(
                 int accessibilityWindowId, long accessibilityNodeId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                long interrogatingTid) throws RemoteException {
+                long interrogatingTid, Bundle arguments) throws RemoteException {
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
@@ -2936,7 +2964,7 @@
             try {
                 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
                         partialInteractiveRegion, interactionId, callback, mFetchFlags | flags,
-                        interrogatingPid, interrogatingTid, spec);
+                        interrogatingPid, interrogatingTid, spec, arguments);
                 return true;
             } catch (RemoteException re) {
                 if (DEBUG) {
@@ -3332,6 +3360,19 @@
         }
 
         @Override
+        public boolean isAccessibilityButtonAvailable() {
+            final UserState userState;
+            synchronized (mLock) {
+                if (!isCalledForCurrentUserLocked()) {
+                    return false;
+                }
+                userState = getCurrentUserStateLocked();
+            }
+
+            return mRequestAccessibilityButton && userState.mIsAccessibilityButtonAvailable;
+        }
+
+        @Override
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
             synchronized (mLock) {
@@ -3544,6 +3585,14 @@
             mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
         }
 
+        public void notifyAccessibilityButtonClickedLocked() {
+            mInvocationHandler.notifyAccessibilityButtonClickedLocked();
+        }
+
+        public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
+            mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available);
+        }
+
         /**
          * Called by the invocation handler to notify the service that the
          * state of magnification has changed.
@@ -3582,6 +3631,36 @@
             }
         }
 
+        private void notifyAccessibilityButtonClickedInternal() {
+            final IAccessibilityServiceClient listener;
+            synchronized (mLock) {
+                listener = mServiceInterface;
+            }
+            if (listener != null) {
+                try {
+                    listener.onAccessibilityButtonClicked();
+                } catch (RemoteException re) {
+                    Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
+                }
+            }
+        }
+
+        private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) {
+            final IAccessibilityServiceClient listener;
+            synchronized (mLock) {
+                listener = mServiceInterface;
+            }
+            if (listener != null) {
+                try {
+                    listener.onAccessibilityButtonAvailabilityChanged(available);
+                } catch (RemoteException re) {
+                    Slog.e(LOG_TAG,
+                            "Error sending accessibility button availability change to " + mService,
+                            re);
+                }
+            }
+        }
+
         private void notifyGestureInternal(int gestureId) {
             final IAccessibilityServiceClient listener;
             synchronized (mLock) {
@@ -3723,6 +3802,8 @@
 
             private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
             private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
+            private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
+            private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
 
             private boolean mIsMagnificationCallbackEnabled = false;
             private boolean mIsSoftKeyboardCallbackEnabled = false;
@@ -3758,6 +3839,15 @@
                         notifySoftKeyboardShowModeChangedInternal(showState);
                     } break;
 
+                    case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: {
+                        notifyAccessibilityButtonClickedInternal();
+                    } break;
+
+                    case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: {
+                        final boolean available = (message.arg1 != 0);
+                        notifyAccessibilityButtonAvailabilityChangedInternal(available);
+                    } break;
+
                     default: {
                         throw new IllegalArgumentException("Unknown message: " + type);
                     }
@@ -3797,6 +3887,17 @@
             public void setSoftKeyboardCallbackEnabled(boolean enabled) {
                 mIsSoftKeyboardCallbackEnabled = enabled;
             }
+
+            public void notifyAccessibilityButtonClickedLocked() {
+                final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED);
+                msg.sendToTarget();
+            }
+
+            public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
+                final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED,
+                        (available ? 1 : 0), 0);
+                msg.sendToTarget();
+            }
         }
     }
 
@@ -4467,7 +4568,7 @@
 
         // Non-transient state.
 
-        public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
+        public final RemoteCallbackList<IAccessibilityManagerClient> mUserClients =
             new RemoteCallbackList<>();
 
         public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
@@ -4501,6 +4602,8 @@
 
         public int mSoftKeyboardShowMode = 0;
 
+        public boolean mIsAccessibilityButtonAvailable;
+
         public boolean mIsTouchExplorationEnabled;
         public boolean mIsTextHighContrastEnabled;
         public boolean mIsEnhancedWebAccessibilityEnabled;
@@ -4575,6 +4678,9 @@
             mIsDisplayMagnificationEnabled = false;
             mIsAutoclickEnabled = false;
             mSoftKeyboardShowMode = 0;
+
+            // Clear state tracked from system UI
+            mIsAccessibilityButtonAvailable = false;
         }
 
         public void destroyUiAutomationService() {
diff --git a/services/autofill/java/com/android/server/autofill/AnchoredWindow.java b/services/autofill/java/com/android/server/autofill/AnchoredWindow.java
index c68ac60..ed0d234 100644
--- a/services/autofill/java/com/android/server/autofill/AnchoredWindow.java
+++ b/services/autofill/java/com/android/server/autofill/AnchoredWindow.java
@@ -17,134 +17,276 @@
 
 import static com.android.server.autofill.Helper.DEBUG;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.os.IBinder;
 import android.util.Slog;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.widget.FrameLayout;
 
-import java.io.PrintWriter;
 /**
  * A window above the application that is smartly anchored to a rectangular region.
  */
-final class AnchoredWindow {
+final class AnchoredWindow implements View.OnLayoutChangeListener, View.OnTouchListener {
     private static final String TAG = "AutoFill";
 
+    private static final int NULL_HEIGHT = -1;
+
     private final WindowManager mWm;
-    private final View mRootView;
-    private final View mView;
-    private final int mWidth;
-    private final int mHeight;
-    private boolean mIsShowing = false;
+    private final IBinder mAppToken;
+    private final View mContentView;
+
+    private final View mWindowSizeListenerView;
+    private final int mMinMargin;
+
+    private int mLastHeight = NULL_HEIGHT;
+    @Nullable
+    private Rect mLastBounds;
+    @Nullable
+    private Rect mLastDisplayBounds;
 
     /**
      * Constructor.
      *
-     * @param wm window manager that draws the view on a window
-     * @param view singleton view in the window
-     * @param width requested width of the view
-     * @param height requested height of the view
+     * @param wm window manager that draws the content on a window
+     * @param appToken token to pass to window manager
+     * @param contentView content of the window
      */
-    AnchoredWindow(WindowManager wm, View view, int width, int height) {
+    AnchoredWindow(WindowManager wm, IBinder appToken, View contentView) {
         mWm = wm;
-        mRootView = wrapView(view, width, height);
-        mView = view;
-        mWidth = width;
-        mHeight = height;
+        mAppToken = appToken;
+        mContentView = contentView;
+
+        mContentView.addOnLayoutChangeListener(this);
+
+        Context context = contentView.getContext();
+
+        mWindowSizeListenerView = new FrameLayout(context);
+        mWindowSizeListenerView.addOnLayoutChangeListener(this);
+
+        mMinMargin = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.autofill_fill_min_margin);
     }
 
     /**
      * Shows the window.
      *
-     * @param bounds the rectangular region this window should be anchored to
+     * @param bounds the region the window should be anchored to
      */
     void show(Rect bounds) {
-        final LayoutParams params = createBaseLayoutParams();
-        params.x = bounds.left;
-        params.y = bounds.bottom;
+        if (DEBUG) Slog.d(TAG, "show bounds=" + bounds);
 
-        if (!mIsShowing) {
-            if (DEBUG) Slog.d(TAG, "adding view " + mView);
-            mWm.addView(mRootView, params);
-        } else {
-            if (DEBUG) Slog.d(TAG, "updating view " + mView);
-            mWm.updateViewLayout(mRootView, params);
+        if (!mWindowSizeListenerView.isAttachedToWindow()) {
+            if (DEBUG) Slog.d(TAG, "adding mWindowSizeListenerView");
+            LayoutParams params = createWindowLayoutParams(
+                    mAppToken,
+                    LayoutParams.FLAG_NOT_TOUCHABLE); // not touchable
+            params.gravity = Gravity.LEFT | Gravity.TOP;
+            params.x = 0;
+            params.y = 0;
+            params.width = LayoutParams.MATCH_PARENT;
+            params.height = LayoutParams.MATCH_PARENT;
+            mWm.addView(mWindowSizeListenerView, params);
         }
-        mIsShowing = true;
+
+        updateBounds(bounds);
     }
 
     /**
      * Hides the window.
      */
     void hide() {
-        if (DEBUG) Slog.d(TAG, "removing view " + mView);
+        if (DEBUG) Slog.d(TAG, "hide");
 
-        if (mIsShowing) {
-            mWm.removeView(mRootView);
+        mLastHeight = NULL_HEIGHT;
+        mLastBounds = null;
+        mLastDisplayBounds = null;
+
+        if (mWindowSizeListenerView.isAttachedToWindow()) {
+            if (DEBUG) Slog.d(TAG, "removing mWindowSizeListenerView");
+            mWm.removeView(mWindowSizeListenerView);
         }
-        mIsShowing = false;
-    }
 
-    /**
-     * Wraps a view with a SelfRemovingView and sets its requested width and height.
-     */
-    private View wrapView(View view, int width, int height) {
-        final ViewGroup viewGroup = new SelfRemovingView(view.getContext());
-        viewGroup.addView(view, new ViewGroup.LayoutParams(width, height));
-        return viewGroup;
-    }
-
-    private static LayoutParams createBaseLayoutParams() {
-        final LayoutParams params = new LayoutParams();
-        // TODO(b/33197203): LayoutParams.TYPE_AUTOFILL
-        params.type = LayoutParams.TYPE_SYSTEM_ALERT;
-        params.flags =
-                LayoutParams.SOFT_INPUT_STATE_UNCHANGED
-                | LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | LayoutParams.FLAG_NOT_FOCUSABLE
-                | LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-        params.gravity = Gravity.TOP | Gravity.LEFT;
-        params.width = LayoutParams.WRAP_CONTENT;
-        params.height = LayoutParams.WRAP_CONTENT;
-        return params;
+        if (mContentView.isAttachedToWindow()) {
+            if (DEBUG) Slog.d(TAG, "removing mContentView");
+            mContentView.setOnTouchListener(null);
+            mWm.removeView(mContentView);
+        }
     }
 
     @Override
-    public String toString() {
-        if (!DEBUG) return super.toString();
-
-        return "AnchoredWindow: [width=" + mWidth + ", height=" + mHeight + ", view=" + mView + "]";
+    public void onLayoutChange(View view, int left, int top, int right, int bottom,
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        if (view == mWindowSizeListenerView) {
+            if (DEBUG) Slog.d(TAG, "onLayoutChange() for mWindowSizeListenerView");
+            // mWindowSizeListenerView layout changed, get the size of the display bounds and update
+            // the window.
+            final Rect displayBounds = new Rect();
+            view.getBoundsOnScreen(displayBounds);
+            updateDisplayBounds(displayBounds);
+        } else if (view == mContentView) {
+            // mContentView layout changed, update the window in case its height changed.
+            if (DEBUG) Slog.d(TAG, "onLayoutChange() for mContentView");
+            updateHeight();
+        }
     }
 
-    void dump(PrintWriter pw) {
-        pw.println("Anchored Window");
-        final String prefix = "  ";
-        pw.print(prefix); pw.print("width: "); pw.println(mWidth);
-        pw.print(prefix); pw.print("height: "); pw.println(mHeight);
-        pw.print(prefix); pw.print("visible: "); pw.println(mIsShowing);
+    // When the window is touched outside, hide the window.
+    @Override
+    public boolean onTouch(View view, MotionEvent event) {
+        if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+            hide();
+            return true;
+        }
+        return false;
     }
 
-    /** FrameLayout that listens for touch events removes itself if the touch event is outside. */
-    private final class SelfRemovingView extends FrameLayout {
-        public SelfRemovingView(Context context) {
-            super(context);
+    private boolean updateHeight() {
+        final Rect displayBounds = mLastDisplayBounds;
+        if (displayBounds == null) {
+            return false;
         }
 
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-                hide();
-                return true;
-            } else {
-                return super.onTouchEvent(event);
+        mContentView.measure(
+                MeasureSpec.makeMeasureSpec(displayBounds.width(), MeasureSpec.AT_MOST),
+                MeasureSpec.makeMeasureSpec(displayBounds.height(), MeasureSpec.AT_MOST));
+        int height = mContentView.getMeasuredHeight();
+        if (height != mLastHeight) {
+            if (DEBUG) Slog.d(TAG, "update height=" + height);
+            mLastHeight = height;
+            update(height, mLastBounds, displayBounds);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private void updateBounds(Rect bounds) {
+        if (!bounds.equals(mLastBounds)) {
+            if (DEBUG) Slog.d(TAG, "update bounds=" + bounds);
+            mLastBounds = bounds;
+
+            update(mLastHeight, bounds, mLastDisplayBounds);
+        }
+    }
+
+    private void updateDisplayBounds(Rect displayBounds) {
+        if (!displayBounds.equals(mLastDisplayBounds)) {
+            if (DEBUG) Slog.d(TAG, "update displayBounds=" + displayBounds);
+            mLastDisplayBounds = displayBounds;
+
+            if (!updateHeight()) {
+                update(mLastHeight, mLastBounds, displayBounds);
             }
         }
     }
+
+    // Updates the window if height, bounds, and displayBounds are not null.
+    // Caller should ensure that something changed before calling.
+    private void update(int height, @Nullable Rect bounds, @Nullable Rect displayBounds) {
+        if (height == NULL_HEIGHT || bounds == null || displayBounds == null) {
+            return;
+        }
+
+        if (DEBUG) Slog.d(TAG, "update height=" + height + ", bounds=" + bounds
+                + ", displayBounds=" + displayBounds);
+
+        final LayoutParams params = createWindowLayoutParams(mAppToken,
+                LayoutParams.FLAG_NOT_TOUCH_MODAL // outside touches go to windows behind us
+                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); // outside touches trigger MotionEvent
+        params.setTitle("AutoFill Fill"); // used for debugging
+        updatePosition(params, height, mMinMargin, bounds, displayBounds);
+        if (!mContentView.isAttachedToWindow()) {
+            if (DEBUG) Slog.d(TAG, "adding mContentView");
+            mWm.addView(mContentView, params);
+            mContentView.setOnTouchListener(this);
+        } else {
+            if (DEBUG) Slog.d(TAG, "updating mContentView");
+            mWm.updateViewLayout(mContentView, params);
+        }
+    }
+
+    /**
+     * Updates the position of the window by altering the {@link LayoutParams}.
+     *
+     * <p>The window can be anchored either above or below the bounds. Anchoring the window below
+     * the bounds is preferred, if it fits. Otherwise, anchor the window on the side with more
+     * space.
+     *
+     * @param params the params to update
+     * @param height the requested height of the window
+     * @param minMargin the minimum margin between the window and the display bounds
+     * @param bounds the region the window should be anchored to
+     * @param displayBounds the region in which the window may be displayed
+     */
+    private static void updatePosition(
+            LayoutParams params,
+            int height,
+            int minMargin,
+            Rect bounds,
+            Rect displayBounds) {
+        boolean below;
+        int verticalSpace;
+        final int verticalSpaceBelow = displayBounds.bottom - bounds.bottom - minMargin;
+        if (height <= verticalSpaceBelow) {
+            // Fits below bounds.
+            below = true;
+            verticalSpace = height;
+        } else {
+            final int verticalSpaceAbove = bounds.top - displayBounds.top - minMargin;
+            if (height <= verticalSpaceAbove) {
+                // Fits above bounds.
+                below = false;
+                verticalSpace = height;
+            } else {
+                // Pick above/below based on which has the most space.
+                if (verticalSpaceBelow >= verticalSpaceAbove) {
+                    below = true;
+                    verticalSpace = verticalSpaceBelow;
+                } else {
+                    below = false;
+                    verticalSpace = verticalSpaceAbove;
+                }
+            }
+        }
+
+        int gravity;
+        int y;
+        if (below) {
+            if (DEBUG) Slog.d(TAG, "anchorBelow");
+            gravity = Gravity.TOP | Gravity.LEFT;
+            y = bounds.bottom - displayBounds.top;
+        } else {
+            if (DEBUG) Slog.d(TAG, "anchorAbove");
+            gravity = Gravity.BOTTOM | Gravity.LEFT;
+            y = displayBounds.bottom - bounds.top;
+        }
+
+        final int x = bounds.left - displayBounds.left;
+
+        params.gravity = gravity;
+        params.x = x;
+        params.y = y;
+        params.width = bounds.width();
+        params.height = verticalSpace;
+    }
+
+    private static LayoutParams createWindowLayoutParams(IBinder appToken, int flags) {
+        final LayoutParams params = new LayoutParams();
+        params.token = appToken;
+        params.type = LayoutParams.TYPE_PHONE;
+        params.flags =
+                flags
+                | LayoutParams.FLAG_NOT_FOCUSABLE // don't receive input events
+                | LayoutParams.FLAG_ALT_FOCUSABLE_IM; // resize for soft input
+        params.format = PixelFormat.TRANSLUCENT;
+        return params;
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index 78436f7..9347350 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -18,8 +18,11 @@
 
 import static android.Manifest.permission.MANAGE_AUTO_FILL;
 import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
+import static com.android.server.autofill.Helper.DEBUG;
+import static com.android.server.autofill.Helper.VERBOSE;
 
 import android.Manifest;
+import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.content.ComponentName;
@@ -34,8 +37,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -43,7 +44,6 @@
 import android.provider.Settings;
 import android.service.autofill.IAutoFillManagerService;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.Slog;
@@ -72,66 +72,47 @@
 public final class AutoFillManagerService extends SystemService {
 
     private static final String TAG = "AutoFillManagerService";
-    static final boolean DEBUG = true; // TODO(b/33197203): change to false once stable
 
-    private static final long SERVICE_BINDING_LIFETIME_MS = 5 * DateUtils.MINUTE_IN_MILLIS;
+    private static final int MSG_START_SESSION = 1;
+    private static final int MSG_UPDATE_SESSION = 2;
+    private static final int MSG_FINISH_SESSION = 3;
+    private static final int MSG_REQUEST_SAVE_FOR_USER = 4;
 
-    private static final int MSG_UNBIND = 1;
-    private static final int MSG_REQUEST_AUTO_FILL_FOR_USER = 2;
-    private static final int MSG_REQUEST_AUTO_FILL = 3;
-    private static final int MSG_ON_VALUE_CHANGED = 4;
-    private static final int MSG_REQUEST_SAVE_FOR_USER = 5;
-
-    private final AutoFillManagerServiceStub mServiceStub;
     private final Context mContext;
-    private final ContentResolver mResolver;
+    private final AutoFillUI mUi;
 
     private final Object mLock = new Object();
 
-    private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() {
-
-        @Override
-        public void executeMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UNBIND: {
-                    synchronized (mLock) {
-                        removeCachedServiceLocked(msg.arg1);
-                    }
-                    return;
-                } case MSG_REQUEST_AUTO_FILL_FOR_USER: {
-                    handleAutoFillForUser(msg.arg1);
-                    return;
-                } case MSG_REQUEST_SAVE_FOR_USER: {
-                    handleSaveForUser(msg.arg1);
-                    return;
-                } case MSG_REQUEST_AUTO_FILL: {
-                    final SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        final int userId = msg.arg1;
-                        final int flags = msg.arg2;
-                        final IBinder activityToken = (IBinder) args.arg1;
-                        final AutoFillId autoFillId = (AutoFillId) args.arg2;
-                        final Rect bounds = (Rect) args.arg3;
-                        handleAutoFill(activityToken, userId, autoFillId, bounds, flags);
-                    } finally {
-                        args.recycle();
-                    }
-                    return;
-                } case MSG_ON_VALUE_CHANGED: {
-                    final SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        final int userId = msg.arg1;
-                        final IBinder activityToken = (IBinder) args.arg1;
-                        final AutoFillId autoFillId = (AutoFillId) args.arg2;
-                        final AutoFillValue newValue = (AutoFillValue) args.arg3;
-                        handleValueChanged(activityToken, userId, autoFillId, newValue);
-                    } finally {
-                        args.recycle();
-                    }
-                    return;
-                } default: {
-                    Slog.w(TAG, "Invalid message: " + msg);
-                }
+    private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+        switch (msg.what) {
+            case MSG_START_SESSION: {
+                final SomeArgs args = (SomeArgs) msg.obj;
+                final int userId = msg.arg1;
+                final IBinder activityToken = (IBinder) args.arg1;
+                final IBinder appCallback = (IBinder) args.arg2;
+                final AutoFillId autoFillId = (AutoFillId) args.arg3;
+                final Rect bounds = (Rect) args.arg4;
+                final AutoFillValue value = (AutoFillValue) args.arg5;
+                handleStartSession(userId, activityToken, appCallback, autoFillId, bounds, value);
+                return;
+            } case MSG_FINISH_SESSION: {
+                handleFinishSession(msg.arg1, (IBinder) msg.obj);
+                return;
+            } case MSG_REQUEST_SAVE_FOR_USER: {
+                handleSaveForUser(msg.arg1);
+                return;
+            } case MSG_UPDATE_SESSION: {
+                final SomeArgs args = (SomeArgs) msg.obj;
+                final IBinder activityToken = (IBinder) args.arg1;
+                final AutoFillId autoFillId = (AutoFillId) args.arg2;
+                final Rect bounds = (Rect) args.arg3;
+                final AutoFillValue value = (AutoFillValue) args.arg4;
+                final int userId = args.argi5;
+                final int flags = args.argi6;
+                handleUpdateSession(userId, activityToken, autoFillId, bounds, value, flags);
+                return;
+            } default: {
+                Slog.w(TAG, "Invalid message: " + msg);
             }
         }
     };
@@ -148,10 +129,10 @@
      * Entries on this cache are added on demand and removed when:
      * <ol>
      *   <li>An auto-fill service app is removed.
-     *   <li>The {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} for an user change.
-     *   <li>It has not been interacted with for {@link #SERVICE_BINDING_LIFETIME_MS} ms.
+     *   <li>The {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} for an user change.\
      * </ol>
      */
+    // TODO(b/33197203): Update the above comment
     @GuardedBy("mLock")
     private SparseArray<AutoFillManagerServiceImpl> mServicesCache = new SparseArray<>();
 
@@ -160,19 +141,14 @@
 
     public AutoFillManagerService(Context context) {
         super(context);
-
         mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
-
         mContext = context;
-
-        mResolver = context.getContentResolver();
-        mServiceStub = new AutoFillManagerServiceStub();
+        mUi = new AutoFillUI(mContext);
     }
 
     @Override
     public void onStart() {
-        if (DEBUG) Slog.d(TAG, "onStart(): binding as " + AUTO_FILL_MANAGER_SERVICE);
-        publishBinderService(AUTO_FILL_MANAGER_SERVICE, mServiceStub);
+        publishBinderService(AUTO_FILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
     }
 
     @Override
@@ -186,61 +162,44 @@
         ComponentName serviceComponent = null;
         ServiceInfo serviceInfo = null;
         final String componentName = Settings.Secure.getStringForUser(
-                mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
+                mContext.getContentResolver(), Settings.Secure.AUTO_FILL_SERVICE, userId);
         if (!TextUtils.isEmpty(componentName)) {
             try {
                 serviceComponent = ComponentName.unflattenFromString(componentName);
                 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0,
                         userId);
             } catch (RuntimeException | RemoteException e) {
-                Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
+                Slog.e(TAG, "Bad auto-fill service name " + componentName, e);
                 return null;
             }
         }
 
-        if (DEBUG) {
-            Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
-                    + serviceComponent + ", info: " + serviceInfo);
-        }
         if (serviceInfo == null) {
-            if (DEBUG) Slog.d(TAG, "no service info for " + serviceComponent);
             return null;
         }
-        return new AutoFillManagerServiceImpl(this, mContext, mLock, mRequestsHistory,
-                userId, serviceInfo.applicationInfo.uid, serviceComponent,
-                SERVICE_BINDING_LIFETIME_MS);
+
+        try {
+            return new AutoFillManagerServiceImpl(mContext, mLock, mRequestsHistory,
+                    userId, serviceComponent, mUi);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, "Auto-fill service not found: " + serviceComponent, e);
+        }
+
+        return null;
     }
 
     /**
      * Gets the service instance for an user.
-     * <p>
-     * First it tries to return the existing instance from the cache; if it's not cached, it creates
-     * a new instance and caches it.
+     *
+     * @return service instance or {@code null} if user does not have a service set.
      */
-    // TODO(b/33197203): make private once AutoFillUi does not uses notifications
+    @Nullable
     AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
         AutoFillManagerServiceImpl service = mServicesCache.get(userId);
-        if (service != null) {
-            if (DEBUG)
-                Log.d(TAG, "reusing cached service for userId " + userId);
-            service.setLifeExpectancy(SERVICE_BINDING_LIFETIME_MS);
-        } else {
+        if (service == null) {
             service = newServiceForUser(userId);
-            if (service == null) {
-                // Already logged
-                return null;
-            }
-            if (DEBUG) Log.d(TAG, "creating new cached service for userId " + userId);
-            service.startLocked();
             mServicesCache.put(userId, service);
         }
-        // Keep service connection alive for a while, in case user needs to interact with it
-        // (for example, to save the data that was inputted in)
-        if (mHandlerCaller.hasMessages(MSG_UNBIND)) {
-            mHandlerCaller.removeMessages(MSG_UNBIND);
-        }
-        mHandlerCaller.sendMessageDelayed(mHandlerCaller.obtainMessageI(MSG_UNBIND, userId),
-                SERVICE_BINDING_LIFETIME_MS);
         return service;
     }
 
@@ -248,35 +207,43 @@
      * Removes a cached service for a given user.
      */
     void removeCachedServiceLocked(int userId) {
-        if (DEBUG) Log.d(TAG, "removing cached service for userId " + userId);
         final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
-        if (service == null) {
-            if (DEBUG) {
-                Log.d(TAG, "removeCachedServiceForUser(): no cached service for userId " + userId);
-            }
-            return;
-        }
-        mServicesCache.delete(userId);
-        service.stopLocked();
-    }
-
-    private void handleAutoFill(IBinder activityToken, int userId, AutoFillId autoFillId,
-            Rect bounds, int flags) {
-        synchronized (mLock) {
-            final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
-            if (service != null) {
-                service.requestAutoFillLocked(activityToken, autoFillId, bounds, flags);
-            }
+        if (service != null) {
+            mServicesCache.delete(userId);
+            service.destroyLocked();
         }
     }
 
-    private void handleValueChanged(IBinder activityToken, int userId, AutoFillId autoFillId,
-            AutoFillValue newValue) {
+    private void handleStartSession(int userId, IBinder activityToken, IBinder appCallback,
+            AutoFillId autoFillId, Rect bounds, AutoFillValue value) {
         synchronized (mLock) {
             final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
-            if (service != null) {
-                service.onValueChangeLocked(activityToken, autoFillId, newValue);
+            if (service == null) {
+                return;
             }
+           service.startSessionLocked(activityToken, appCallback, autoFillId, bounds, value);
+        }
+    }
+
+    private void handleFinishSession(int userId, IBinder activityToken) {
+        synchronized (mLock) {
+            final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+            if (service == null) {
+                return;
+            }
+            service.finishSessionLocked(activityToken);
+        }
+    }
+
+    private void handleUpdateSession(int userId, IBinder activityToken, AutoFillId autoFillId,
+            Rect bounds, AutoFillValue value, int flags) {
+        synchronized (mLock) {
+            final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+            if (service == null) {
+                return;
+            }
+
+            service.updateSessionLocked(activityToken, autoFillId, bounds, value, flags);
         }
     }
 
@@ -291,98 +258,70 @@
         return topActivities.get(0);
     }
 
-    private void handleAutoFillForUser(int userId) {
-        if (DEBUG) Slog.d(TAG, "handler.requestAutoFillForUser(): id=" + userId);
-        final IBinder activityToken = getTopActivityForUser();
-        if (activityToken == null) {
-            return;
-        }
-
-        synchronized (mLock) {
-            final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
-            if (service == null) {
-                Slog.w(TAG, "no service for user " + userId);
-                return;
-            }
-            service.requestAutoFillLocked(activityToken, null, null, 0);
-        }
-    }
-
     private void handleSaveForUser(int userId) {
-        if (DEBUG) Slog.d(TAG, "handler.handleSaveForUser(): id=" + userId);
         final IBinder activityToken = getTopActivityForUser();
-        if (activityToken == null) {
-            return;
-        }
+        if (activityToken != null) {
+            synchronized (mLock) {
+                final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+                if (service == null) {
+                    Log.w(TAG, "handleSaveForUser(): no cached service for userId " + userId);
+                    return;
+                }
 
-        synchronized (mLock) {
-            final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
-            if (service == null) {
-                Slog.w(TAG, "no service for user " + userId);
-                return;
+                service.requestSaveForUserLocked(activityToken);
             }
-            service.requestSaveForUserLocked(activityToken);
         }
     }
 
-    private IBinder getTopActivity() {
-        final int uid = Binder.getCallingUid();
-        final IBinder activityToken = LocalServices.getService(ActivityManagerInternal.class)
-                .getTopVisibleActivity(uid);
-        if (activityToken == null) {
-            // Make sure its called by the top activity.
-            if (uid == Process.SYSTEM_UID) {
-                // TODO(b/33197203, b/34819567, b/34171325): figure out proper way to handle it
-                if (DEBUG) Log.w(TAG, "requestAutoFill(): ignoring call from system");
-
-                return null;
-            }
-            throw new SecurityException("uid " + uid + " does not own the top activity");
-        }
-
-        return activityToken;
-    }
-
     final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
 
         @Override
-        public void requestAutoFill(AutoFillId id, Rect bounds, int flags) {
-            if (DEBUG) Slog.d(TAG, "requestAutoFill: flags=" + flags + ", autoFillId=" + id
-                    + ", bounds=" + bounds);
+        public void startSession(IBinder activityToken, IBinder appCallback, AutoFillId autoFillId,
+                Rect bounds, AutoFillValue value) throws RemoteException {
+            // TODO(b/33197203): make sure it's called by resumed / focused activity
 
-            final IBinder activityToken = getTopActivity();
-            if (activityToken != null) {
-                mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIIOOO(MSG_REQUEST_AUTO_FILL,
-                        UserHandle.getCallingUserId(), flags, activityToken, id, bounds));
+            final int userId = UserHandle.getCallingUserId();
+            if (VERBOSE) {
+                Slog.v(TAG, "startSession: autoFillId=" + autoFillId + ", bounds=" + bounds
+                        + ", value=" + value);
             }
+
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = activityToken;
+            args.arg2 = appCallback;
+            args.arg3 = autoFillId;
+            args.arg4 = bounds;
+            args.arg5 = value;
+
+            mHandlerCaller.sendMessage(mHandlerCaller.getHandler().obtainMessage(MSG_START_SESSION,
+                    userId, 0, args));
         }
 
         @Override
-        public void requestAutoFillForUser(int userId) {
-            mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        public void updateSession(IBinder activityToken, AutoFillId id, Rect bounds,
+                AutoFillValue value, int flags) throws RemoteException {
+            if (DEBUG) {
+                Slog.d(TAG, "updateSession: flags=" + flags + ", autoFillId=" + id
+                        + ", bounds=" + bounds + ", value=" + value);
+            }
 
-            mHandlerCaller.sendMessage(
-                    mHandlerCaller.obtainMessageI(MSG_REQUEST_AUTO_FILL_FOR_USER, userId));
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOII(MSG_UPDATE_SESSION,
+                    activityToken, id, bounds, value, UserHandle.getCallingUserId(), flags));
+        }
+
+        @Override
+        public void finishSession(IBinder activityToken) throws RemoteException {
+            if (VERBOSE) Slog.v(TAG, "finishSession(): " + activityToken);
+
+            mHandlerCaller.sendMessage(mHandlerCaller.getHandler().obtainMessage(MSG_FINISH_SESSION,
+                    UserHandle.getCallingUserId(), 0, activityToken));
         }
 
         @Override
         public void requestSaveForUser(int userId) {
             mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
-
-            mHandlerCaller.sendMessage(
-                    mHandlerCaller.obtainMessageI(MSG_REQUEST_SAVE_FOR_USER, userId));
-        }
-
-        @Override
-        public void onValueChanged(AutoFillId id, AutoFillValue value) {
-            if (DEBUG) Slog.d(TAG, "onValueChanged(): id=" + id + ", value=" + value);
-
-            final IBinder activityToken = getTopActivity();
-
-            if (activityToken != null) {
-                mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOOO(MSG_ON_VALUE_CHANGED,
-                        UserHandle.getCallingUserId(), activityToken, id, value));
-            }
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageI(MSG_REQUEST_SAVE_FOR_USER,
+                    userId));
         }
 
         @Override
@@ -407,6 +346,7 @@
                         impl.dumpLocked("  ", pw);
                     }
                 }
+                mUi.dump(pw);
             }
             pw.println("Requests history:");
             mRequestsHistory.reverseDump(fd, pw, args);
@@ -430,7 +370,6 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
-            if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId);
             synchronized (mLock) {
                 removeCachedServiceLocked(userId);
             }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index 42e4fd3..9e0b31a 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -16,15 +16,17 @@
 
 package com.android.server.autofill;
 
-import static android.service.autofill.AutoFillService.FLAG_AUTHENTICATION_ERROR;
-import static android.service.autofill.AutoFillService.FLAG_AUTHENTICATION_REQUESTED;
-import static android.service.autofill.AutoFillService.FLAG_AUTHENTICATION_SUCCESS;
-import static android.view.autofill.AutoFillManager.FLAG_UPDATE_UI_SHOW;
-import static android.view.autofill.AutoFillManager.FLAG_UPDATE_UI_HIDE;
+import static android.service.autofill.AutoFillService.EXTRA_ACTIVITY_TOKEN;
+import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
+import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
+import static android.view.autofill.AutoFillManager.FLAG_FOCUS_GAINED;
+import static android.view.autofill.AutoFillManager.FLAG_FOCUS_LOST;
+import static android.view.autofill.AutoFillManager.FLAG_START_SESSION;
+import static android.view.autofill.AutoFillManager.FLAG_VALUE_CHANGED;
 
 import static com.android.server.autofill.Helper.DEBUG;
 import static com.android.server.autofill.Helper.VERBOSE;
-import static com.android.server.autofill.Helper.bundleToString;
+import static com.android.server.autofill.Helper.findValue;
 
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -38,47 +40,36 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ServiceConnection;
+import android.content.IntentSender;
 import android.content.pm.PackageManager;
 import android.graphics.Rect;
-import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.IFingerprintService;
-import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.os.Binder;
 import android.os.Bundle;
-import android.os.DeadObjectException;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.Looper;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
 import android.service.autofill.AutoFillService;
 import android.service.autofill.AutoFillServiceInfo;
+import android.service.autofill.FillCallback;
 import android.service.autofill.IAutoFillAppCallback;
-import android.service.autofill.IAutoFillServerCallback;
 import android.service.autofill.IAutoFillService;
-import android.service.voice.VoiceInteractionSession;
+import android.service.autofill.IFillCallback;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.LocalLog;
-import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
-import android.util.SparseArray;
-import android.util.TimeUtils;
 import android.view.autofill.AutoFillId;
 import android.view.autofill.AutoFillValue;
 import android.view.autofill.Dataset;
 import android.view.autofill.FillResponse;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.IResultReceiver;
 import com.android.server.FgThread;
 
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -91,28 +82,16 @@
 
     private static final String TAG = "AutoFillManagerServiceImpl";
 
-    /** Used do assign ids to new ServerCallback instances. */
-    private static int sSessionIdCounter = 0;
+    private static final int MSG_SERVICE_SAVE = 1;
 
     private final int mUserId;
-    private final int mUid;
     private final ComponentName mComponent;
     private final String mComponentName;
     private final Context mContext;
     private final IActivityManager mAm;
     private final Object mLock;
     private final AutoFillServiceInfo mInfo;
-    private final AutoFillManagerService mManagerService;
-
-    // Token used for fingerprint authentication
-    // TODO(b/33197203): create on demand?
-    private final IBinder mAuthToken = new Binder();
-
-    private final IFingerprintService mFingerprintService =
-            IFingerprintService.Stub.asInterface(ServiceManager.getService("fingerprint"));
-
-    @GuardedBy("mLock")
-    private final List<QueuedRequest> mQueuedRequests = new LinkedList<>();
+    private final AutoFillUI mUi;
 
     private final LocalLog mRequestsHistory;
 
@@ -122,21 +101,25 @@
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
                 final String reason = intent.getStringExtra("reason");
                 if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
-
-                synchronized (mLock) {
-                    final int size = mSessions.size();
-                    for (int i = 0; i < size; i++) {
-                        final Session session = mSessions.valueAt(i);
-                        // TODO(b/33197203): invalidate the sessions instead?
-                        session.mUi.closeAll();
-                    }
-                }
+                mUi.hideAll();
             }
         }
     };
 
+    private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+        switch (msg.what) {
+            case MSG_SERVICE_SAVE:
+                handleSessionSave((IBinder) msg.obj);
+                break;
+            default:
+                Slog.d(TAG, "invalid msg: " + msg);
+        }
+    };
+
+    private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(),
+            mHandlerCallback, true);
     /**
-     * Cache of pending {@link Session}s, keyed by {@link Session#mId}.
+     * Cache of pending {@link Session}s, keyed by {@code activityToken}.
      *
      * <p>They're kept until the {@link AutoFillService} finished handling a request, an error
      * occurs, or the session times out.
@@ -144,237 +127,127 @@
     // TODO(b/33197203): need to make sure service is bound while callback is pending and/or
     // use WeakReference
     @GuardedBy("mLock")
-    private static final SparseArray<Session> mSessions = new SparseArray<>();
-
-    private final ServiceConnection mConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) Slog.d(TAG, "onServiceConnected():" + name);
-            synchronized (mLock) {
-                mService = IAutoFillService.Stub.asInterface(service);
-                try {
-                    mService.onConnected();
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Exception on service.onConnected(): " + e);
-                    return;
-                }
-                if (!mQueuedRequests.isEmpty()) {
-                    if (DEBUG) Slog.d(TAG, "queued requests:" + mQueuedRequests.size());
-                }
-                for (final QueuedRequest request: mQueuedRequests) {
-                    requestAutoFillLocked(request.activityToken, request.autoFillId,
-                            request.bounds, request.flags, false);
-                }
-                mQueuedRequests.clear();
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) Slog.d(TAG, name + " disconnected");
-            synchronized (mLock) {
-                mService = null;
-                mManagerService.removeCachedServiceLocked(mUserId);
-            }
-        }
-    };
+    private final ArrayMap<IBinder, Session> mSessions = new ArrayMap<>();
 
     /**
-     * Receiver of assist data from the app's {@link Activity}, uses the {@code resultData} as
-     * the {@link Session#mId}.
+     * Receiver of assist data from the app's {@link Activity}.
      */
     private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
         @Override
         public void send(int resultCode, Bundle resultData) throws RemoteException {
             if (DEBUG) Slog.d(TAG, "resultCode on mAssistReceiver: " + resultCode);
 
-            final IBinder appBinder = resultData.getBinder(AutoFillService.KEY_CALLBACK);
-            if (appBinder == null) {
-                Slog.w(TAG, "no app callback on mAssistReceiver's resultData");
+            final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
+
+            if (structure == null) {
+                Slog.w(TAG, "no assist structure for id " + resultCode);
                 return;
             }
-            final AssistStructure structure = resultData
-                    .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
 
+            final Bundle receiverExtras = resultData.getBundle(KEY_RECEIVER_EXTRAS);
+            if (receiverExtras == null) {
+                // Should not happen
+                Slog.wtf(TAG, "No " + KEY_RECEIVER_EXTRAS + " on receiver");
+                return;
+            }
+
+            final IBinder activityToken = receiverExtras.getBinder(EXTRA_ACTIVITY_TOKEN);
             final Session session;
             synchronized (mLock) {
-                session = mSessions.get(resultCode);
+                session = mSessions.get(activityToken);
                 if (session == null) {
-                    Slog.w(TAG, "no server callback for id " + resultCode);
+                    Slog.w(TAG, "no server session for activityToken " + activityToken);
                     return;
                 }
-                session.setAppCallbackLocked(appBinder);
                 // TODO(b/33197203): since service is fetching the data (to use for save later),
                 // we should optimize what's sent (for example, remove layout containers,
                 // color / font info, etc...)
                 session.mStructure = structure;
-
-                // TODO(b/33197203, b/33269702): Must fetch the data so it's available later on
-                // handleSave(), even if if the activity is gone by then, but structure.ensureData()
-                // gives a ONE_WAY warning because system_service could block on app calls.
-                // We need to change AssistStructure so it provides a "one-way" writeToParcel()
-                // method that sends all the data
-                structure.ensureData();
-
-                structure.sanitizeForParceling(true);
-                if (VERBOSE) {
-                    Slog.v(TAG, "Dumping " + structure + " before calling service.autoFill()");
-                    structure.dump();
-                }
-                mService.autoFill(structure, session.mServerCallback);
             }
+
+
+            // TODO(b/33197203, b/33269702): Must fetch the data so it's available later on
+            // handleSave(), even if if the activity is gone by then, but structure.ensureData()
+            // gives a ONE_WAY warning because system_service could block on app calls.
+            // We need to change AssistStructure so it provides a "one-way" writeToParcel()
+            // method that sends all the data
+            structure.ensureData();
+
+            // Sanitize structure before it's sent to service.
+            structure.sanitizeForParceling(true);
+
+            // TODO(b/33197203): Need to pipe the bundle
+            session.mRemoteFillService.onFillRequest(structure, null);
         }
     };
 
-    @GuardedBy("mLock")
-    private IAutoFillService mService;
-    @GuardedBy("mLock")
-    private boolean mBound;
-    @GuardedBy("mLock")
-    private boolean mValid;
-
-    // Estimated time when the service will be evicted from the cache.
-    long mEstimateTimeOfDeath;
-
-    AutoFillManagerServiceImpl(AutoFillManagerService managerService, Context context, Object lock,
-            LocalLog requestsHistory, int userId, int uid, ComponentName component, long ttl) {
-        mManagerService = managerService;
+    AutoFillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
+            int userId, ComponentName component, AutoFillUI ui)
+            throws PackageManager.NameNotFoundException {
         mContext = context;
         mLock = lock;
         mRequestsHistory = requestsHistory;
         mUserId = userId;
-        mUid = uid;
         mComponent = component;
         mComponentName = mComponent.flattenToShortString();
         mAm = ActivityManager.getService();
-        setLifeExpectancy(ttl);
+        mUi = ui;
+        mInfo = new AutoFillServiceInfo(context.getPackageManager(), component, mUserId);
 
-        final AutoFillServiceInfo info;
-        try {
-            info = new AutoFillServiceInfo(context.getPackageManager(), component, mUserId);
-        } catch (PackageManager.NameNotFoundException e) {
-            Slog.w(TAG, "Auto-fill service not found: " + component, e);
-            mInfo = null;
-            mValid = false;
-            return;
-        }
-        mInfo = info;
-        if (mInfo.getParseError() != null) {
-            Slog.w(TAG, "Bad auto-fill service: " + mInfo.getParseError());
-            mValid = false;
-            return;
-        }
-
-        mValid = true;
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
     }
 
-    void setLifeExpectancy(long ttl) {
-        mEstimateTimeOfDeath = SystemClock.uptimeMillis() + ttl;
-    }
-
-    void startLocked() {
-        if (DEBUG) Slog.d(TAG, "startLocked()");
-
-        final Intent intent = new Intent(AutoFillService.SERVICE_INTERFACE);
-        intent.setComponent(mComponent);
-        mBound = mContext.bindServiceAsUser(intent, mConnection,
-                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUserId));
-
-        if (!mBound) {
-            Slog.w(TAG, "Failed binding to auto-fill service " + mComponent);
-            return;
-        }
-        if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
-    }
-
-    /**
-     * Asks service to auto-fill an activity.
-     *
-     * @param activityToken activity token.
-     * @param autoFillId id of the view that requested auto-fill.
-     * @param bounds boundaries of the view that requested auto-fill.
-     * @param flags optional flags.
-     */
-    void requestAutoFillLocked(IBinder activityToken, @Nullable AutoFillId autoFillId,
-            @Nullable Rect bounds, int flags) {
-        if (!mBound) {
-            Slog.w(TAG, "requestAutoFillLocked() failed because it's not bound to service");
-            return;
-        }
-
-        requestAutoFillLocked(activityToken, autoFillId, bounds, flags, true);
-    }
 
     /**
      * Used by {@link AutoFillManagerServiceShellCommand} to request save for the current top app.
      */
     void requestSaveForUserLocked(IBinder activityToken) {
-        if (!mBound) {
-            Slog.w(TAG, "requestSaveForUserLocked() failed because it's not bound to service");
-            return;
-        }
-        if (mService == null) {
-            Slog.w(TAG, "requestSaveForUserLocked: service not set");
-            return;
-        }
-
-        final Session session = getSessionByTokenLocked(activityToken);
+        final Session session = mSessions.get(activityToken);
         if (session == null) {
             Slog.w(TAG, "requestSaveForUserLocked(): no session for " + activityToken);
             return;
         }
 
-        session.onSaveLocked();
+        session.callSaveLocked();
     }
 
-    private void requestAutoFillLocked(IBinder activityToken, @Nullable AutoFillId autoFillId,
-            @Nullable Rect bounds, int flags, boolean queueIfNecessary) {
-        if (mService == null) {
-            if (!queueIfNecessary) {
-                Slog.w(TAG, "requestAutoFillLocked(): service is null");
-                return;
-            }
-            if (DEBUG) Slog.d(TAG, "requestAutoFillLocked(): service not set yet, queuing it");
-            mQueuedRequests.add(new QueuedRequest(activityToken, autoFillId, bounds, flags));
-            return;
-        }
-
-        final String historyItem = "s=" + mComponentName + " u=" + mUserId + " f=" + flags
-                + " a=" + activityToken + " i=" + autoFillId + " b=" + bounds;
+    void startSessionLocked(IBinder activityToken, IBinder appCallbackToken, AutoFillId autoFillId,
+            Rect bounds, AutoFillValue value) {
+        final String historyItem = "s=" + mComponentName + " u=" + mUserId + " a=" + activityToken
+                + " i=" + autoFillId + " b=" + bounds + " v=" + value;
         mRequestsHistory.log(historyItem);
 
         // TODO(b/33197203): Handle partitioning
-        Session session = getSessionByTokenLocked(activityToken);
+        final Session session = mSessions.get(activityToken);
+        if (session != null) {
+            // Already started...
+            return;
+        }
+
+        final Session newSession = createSessionByTokenLocked(activityToken, appCallbackToken);
+        newSession.updateLocked(autoFillId, bounds, value, FLAG_START_SESSION);
+        newSession.enableSessionLocked();
+    }
+
+    void finishSessionLocked(IBinder activityToken) {
+        if (DEBUG) Slog.d(TAG, "finishSessionLocked(): " + activityToken);
+        final Session session = mSessions.get(activityToken);
 
         if (session == null) {
-            session = createSessionByTokenLocked(activityToken);
-        } else {
-            if (DEBUG) Slog.d(TAG, "reusing session for " + activityToken + ": " + session.mId);
+            Slog.w(TAG, "finishSessionLocked(): no session for " + activityToken);
+            return;
         }
 
-        session.updateAutoFillInput(flags, autoFillId, null, bounds);
+        mUi.hideFillUi();
+        session.showSaveLocked();
     }
 
-    private Session getSessionByTokenLocked(IBinder activityToken) {
-        final int size = mSessions.size();
-        for (int i = 0; i < size; i++) {
-            final Session session = mSessions.valueAt(i);
-            if (activityToken.equals(session.mActivityToken.get())) {
-                return session;
-            }
-        }
-        return null;
-    }
+    private Session createSessionByTokenLocked(IBinder activityToken, IBinder appCallbackToken) {
 
-    private Session createSessionByTokenLocked(IBinder activityToken) {
-        final int sessionId = ++sSessionIdCounter;
-        if (DEBUG) Slog.d(TAG, "creating session for " + activityToken + ": " + sessionId);
-
-        final Session newSession = new Session(sessionId, activityToken);
-        mSessions.put(sessionId, newSession);
+        final Session newSession = new Session(mContext, activityToken, appCallbackToken);
+        mSessions.put(activityToken, newSession);
 
         /*
          * TODO(b/33197203): apply security checks below:
@@ -385,7 +258,9 @@
          */
         try {
             // TODO(b/33197203): add MetricsLogger call
-            if (!mAm.requestAutoFillData(mAssistReceiver, null, sessionId, activityToken)) {
+            final Bundle receiverExtras = new Bundle();
+            receiverExtras.putBinder(EXTRA_ACTIVITY_TOKEN, activityToken);
+            if (!mAm.requestAutoFillData(mAssistReceiver, receiverExtras, activityToken)) {
                 // TODO(b/33197203): might need a way to warn user (perhaps a new method on
                 // AutoFillService).
                 Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
@@ -396,94 +271,53 @@
         return newSession;
     }
 
-    /**
-     * Callback indicating the value of a field change in the app.
-     */
-    void onValueChangeLocked(IBinder activityToken, AutoFillId autoFillId, AutoFillValue newValue) {
+    void updateSessionLocked(IBinder activityToken, AutoFillId autoFillId, Rect bounds,
+            AutoFillValue value, int flags) {
+
         // TODO(b/33197203): add MetricsLogger call
-        final Session session = getSessionByTokenLocked(activityToken);
+        final Session session = mSessions.get(activityToken);
         if (session == null) {
-            Slog.w(TAG, "onValueChangeLocked(): session gone for " + activityToken);
+            Slog.w(TAG, "updateSessionLocked(): session gone for " + activityToken);
             return;
         }
 
-        session.updateValueLocked(autoFillId, newValue);
+        session.updateLocked(autoFillId, bounds, value, flags);
     }
 
-    void stopLocked() {
-        if (DEBUG) Slog.d(TAG, "stopLocked()");
+    private void handleSessionSave(IBinder activityToken) {
 
-        // Sanity check.
-        if (mService == null) {
-            Slog.w(TAG, "service already null on shutdown");
-            return;
-        }
-        try {
-            mService.onDisconnected();
-        } catch (RemoteException e) {
-            if (! (e instanceof DeadObjectException)) {
-                Slog.w(TAG, "Exception calling service.onDisconnected(): " + e);
+        synchronized (mLock) {
+            final Session session = mSessions.get(activityToken);
+            if (session == null) {
+                Slog.w(TAG, "handleSessionSave(): already gone: " + activityToken);
+
+                return;
             }
-        } finally {
-            mService = null;
-        }
-
-        if (mBound) {
-            mContext.unbindService(mConnection);
-            mBound = false;
-        }
-        if (mValid) {
-            mContext.unregisterReceiver(mBroadcastReceiver);
+            session.callSaveLocked();
         }
     }
 
-    void removeSessionLocked(int id) {
-        if (DEBUG) Slog.d(TAG, "Removing session " + id);
-        mSessions.remove(id);
+    void destroyLocked() {
+        if (VERBOSE) Slog.v(TAG, "destroyLocked()");
 
-        // TODO(b/33197203): notify mService so it can invalidate the FillCallback / SaveCallback
-        // and cached AssistStructures
+        mContext.unregisterReceiver(mBroadcastReceiver);
+        for (Session session : mSessions.values()) {
+            session.destroyLocked();
+        }
+        mSessions.clear();
     }
 
     void dumpLocked(String prefix, PrintWriter pw) {
-        if (!mValid) {
-            pw.print("  NOT VALID: ");
-            if (mInfo == null) {
-                pw.println("no info");
-            } else {
-                pw.println(mInfo.getParseError());
-            }
-            return;
-        }
-
         final String prefix2 = prefix + "  ";
 
-        pw.print(prefix); pw.print("mUserId="); pw.println(mUserId);
-        pw.print(prefix); pw.print("mUid="); pw.println(mUid);
-        pw.print(prefix); pw.print("mComponent="); pw.println(mComponentName);
-        pw.print(prefix); pw.print("mService: "); pw.println(mService);
-        pw.print(prefix); pw.print("mBound="); pw.println(mBound);
-        pw.print(prefix); pw.print("mEstimateTimeOfDeath=");
-            TimeUtils.formatDuration(mEstimateTimeOfDeath, SystemClock.uptimeMillis(), pw);
-            pw.println();
-        pw.print(prefix); pw.print("mAuthToken: "); pw.println(mAuthToken);
+        pw.print(prefix); pw.println("Component:"); pw.println(mComponentName);
 
-        if (DEBUG) {
+        if (VERBOSE) {
             // ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
             pw.print(prefix); pw.println("ServiceInfo:");
             mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
         }
 
-        if (mQueuedRequests.isEmpty()) {
-            pw.print(prefix); pw.println("No queued requests");
-        } else {
-            pw.print(prefix); pw.println("Queued requests:");
-            for (int i = 0; i < mQueuedRequests.size(); i++) {
-                pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mQueuedRequests.get(i));
-            }
-        }
-
-        pw.print(prefix); pw.print("sSessionIdCounter="); pw.println(sSessionIdCounter);
         final int size = mSessions.size();
         if (size == 0) {
             pw.print(prefix); pw.println("No sessions");
@@ -498,32 +332,10 @@
 
     @Override
     public String toString() {
-        return "AutoFillManagerServiceImpl: [userId=" + mUserId + ", uid=" + mUid
+        return "AutoFillManagerServiceImpl: [userId=" + mUserId
                 + ", component=" + mComponentName + "]";
     }
 
-    private static final class QueuedRequest {
-        final IBinder activityToken;
-        final AutoFillId autoFillId;
-        final Rect bounds;
-        final int flags;
-
-        QueuedRequest(IBinder activityToken, AutoFillId autoFillId, Rect bounds, int flags) {
-            this.activityToken = activityToken;
-            this.autoFillId = autoFillId;
-            this.bounds = bounds;
-            this.flags = flags;
-        }
-
-        @Override
-        public String toString() {
-            if (!DEBUG) return super.toString();
-
-            return "QueuedRequest: [flags=" + flags + ", token=" + activityToken
-                    + ", id=" + autoFillId + ", bounds=" + bounds;
-        }
-    }
-
     /**
      * State for a given view with a AutoFillId.
      *
@@ -539,13 +351,17 @@
                     @Nullable AutoFillValue value);
         }
 
+        final AutoFillId mId;
         private final Listener mListener;
         // // TODO(b/33197203): does it really need a reference to the session's response?
         private FillResponse mResponse;
         private AutoFillValue mAutoFillValue;
         private Rect mBounds;
 
-        ViewState(Listener listener) {
+        private boolean mValueUpdated;
+
+        ViewState(AutoFillId id, Listener listener) {
+            mId = id;
             mListener = listener;
         }
 
@@ -553,15 +369,13 @@
          * Response should only be set once.
          */
         void setResponse(FillResponse response) {
-            if (mResponse != null) {
-                Slog.e(TAG, "ViewState response set more than once");
-                return;
-            }
             mResponse = response;
-
             maybeCallOnFillReady();
         }
 
+        // TODO(b/33197203): need to refactor / rename / document this method to make it clear that
+        // it can change  the value and update the UI; similarly, should replace code that
+        // directly sets mAutoFilLValue to use encapsulation.
         void update(@Nullable AutoFillValue autoFillValue, @Nullable Rect bounds) {
             if (autoFillValue != null) {
                 mAutoFillValue = autoFillValue;
@@ -587,9 +401,17 @@
         public String toString() {
             if (!DEBUG) return super.toString();
 
-            return "ViewState: [response=" + mResponse + ", value=" + mAutoFillValue
-                    + ", bounds=" + mBounds + "]";
+            return "ViewState: [id=" + mId + ", value=" + mAutoFillValue + ", bounds=" + mBounds
+                    + ", updated = " + mValueUpdated + "]";
         }
+
+        void dump(String prefix, PrintWriter pw) {
+            pw.print(prefix); pw.print("id:" ); pw.println(mId);
+            pw.print(prefix); pw.print("value:" ); pw.println(mAutoFillValue);
+            pw.print(prefix); pw.print("updated:" ); pw.println(mValueUpdated);
+            pw.print(prefix); pw.print("bounds:" ); pw.println(mBounds);
+        }
+
     }
 
     /**
@@ -608,280 +430,206 @@
     // - On all authentication scenarios.
     // - When user does not interact back after a while.
     // - When service is unbound.
-    final class Session implements ViewState.Listener {
-
-        private final AutoFillUI mUi;
-        private final WeakReference<IBinder> mActivityToken;
+    final class Session implements RemoteFillService.FillServiceCallbacks, ViewState.Listener,
+            AutoFillUI.AutoFillUiCallback {
+        private final IBinder mActivityToken;
 
         @GuardedBy("mLock")
         private final Map<AutoFillId, ViewState> mViewStates = new ArrayMap<>();
+
         @GuardedBy("mLock")
         @Nullable
         private ViewState mCurrentViewState;
 
-        private IAutoFillAppCallback mAppCallback;
+        private final IAutoFillAppCallback mAppCallback;
+
+        @GuardedBy("mLock")
+        RemoteFillService mRemoteFillService;
 
         // TODO(b/33197203): Get a response per view instead of per activity.
         @GuardedBy("mLock")
         private FillResponse mCurrentResponse;
-        @GuardedBy("mLock")
-        private FillResponse mResponseRequiringAuth;
-        @GuardedBy("mLock")
-        private Dataset mDatasetRequiringAuth;
-
-        /**
-         * Used to auto-fill the activity directly when the FillCallback.onResponse() is called as
-         * the result of a successful user authentication on service's side.
-         */
-        @GuardedBy("mLock")
-        private boolean mAutoFillDirectly;
 
         /**
          * Used to remember which {@link Dataset} filled the session.
          */
+        // TODO(b/33197203): might need more than one once we support partitions
         @GuardedBy("mLock")
         private Dataset mAutoFilledDataset;
 
         /**
-         * Map of ids that must be updated so they're send to {@link #onSaveLocked()}.
-         */
-        @GuardedBy("mLock")
-        private Map<AutoFillId, AutoFillValue> mUpdatedValues;
-
-        /**
          * Assist structure sent by the app; it will be updated (sanitized, change values for save)
          * before sent to {@link AutoFillService}.
          */
+        @GuardedBy("mLock")
         private AssistStructure mStructure;
 
-        // TODO(b/33197203): use handler to handle results?
-        // TODO(b/33197203): handle all callback methods and/or cancelation?
-        private IFingerprintServiceReceiver mServiceReceiver =
-                new IFingerprintServiceReceiver.Stub() {
+        private Session(Context context, IBinder activityToken, IBinder appCallback) {
+            mRemoteFillService = new RemoteFillService(context, mComponent, mUserId, this);
+            mActivityToken = activityToken;
 
-            @Override
-            public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
-                if (DEBUG) Slog.d(TAG, "onEnrollResult()");
-            }
-
-            @Override
-            public void onAcquired(long deviceId, int acquiredInfo, int vendorCode) {
-                if (DEBUG) Slog.d(TAG, "onAcquired()");
-            }
-
-            @Override
-            public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
-                if (DEBUG) Slog.d(TAG, "onAuthenticationSucceeded(): " + fp.getGroupId());
-
-                // First, check what was authenticated, a response or a dataset.
-                // Then, decide how to handle it:
-                // - If service provided data, handle them directly.
-                // - Otherwise, notify service.
-
-                mAutoFillDirectly = true;
-
-                if (mDatasetRequiringAuth != null) {
-                    if (mDatasetRequiringAuth.isEmpty()) {
-                        notifyDatasetAuthenticationResult(mDatasetRequiringAuth.getExtras(),
-                                FLAG_AUTHENTICATION_SUCCESS);
-                    } else {
-                        autoFillApp(mDatasetRequiringAuth);
-                    }
-                } else if (mResponseRequiringAuth != null) {
-                    final List<Dataset> datasets = mResponseRequiringAuth.getDatasets();
-                    if (datasets.isEmpty()) {
-                        notifyResponseAuthenticationResult(mResponseRequiringAuth.getExtras(),
-                                FLAG_AUTHENTICATION_SUCCESS);
-                    } else {
-                        showResponseLocked(mResponseRequiringAuth, true);
-                    }
-                } else {
-                    Slog.w(TAG, "onAuthenticationSucceeded(): no response or dataset");
-                }
-
-                mUi.dismissFingerprintRequest(true);
-            }
-
-            @Override
-            public void onAuthenticationFailed(long deviceId) {
-                if (DEBUG) Slog.d(TAG, "onAuthenticationFailed()");
-                // Do nothing - onError() will be called after a few failures...
-            }
-
-            @Override
-            public void onError(long deviceId, int error, int vendorCode) {
-                if (DEBUG) Slog.d(TAG, "onError()");
-
-                // Notify service so it can fallback to its own authentication
-                if (mDatasetRequiringAuth != null) {
-                    notifyDatasetAuthenticationResult(mDatasetRequiringAuth.getExtras(),
-                            FLAG_AUTHENTICATION_ERROR);
-                } else if (mResponseRequiringAuth != null) {
-                    notifyResponseAuthenticationResult(mResponseRequiringAuth.getExtras(),
-                            FLAG_AUTHENTICATION_ERROR);
-                } else {
-                    Slog.w(TAG, "onError(): no response or dataset");
-                }
-
-                mUi.dismissFingerprintRequest(false);
-            }
-
-            @Override
-            public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
-                if (DEBUG) Slog.d(TAG, "onRemoved()");
-            }
-
-            @Override
-            public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) {
-                if (DEBUG) Slog.d(TAG, "onEnumerated()");
-            }
-        };
-
-        private IAutoFillServerCallback mServerCallback = new IAutoFillServerCallback.Stub() {
-            @Override
-            public void showResponse(FillResponse response) {
-                // TODO(b/33197203): add MetricsLogger call
-                if (response == null) {
-                    if (DEBUG) Slog.d(TAG, "showResponse(): null response");
+            mAppCallback = IAutoFillAppCallback.Stub.asInterface(appCallback);
+            try {
+                appCallback.linkToDeath(() -> {
+                    if (DEBUG) Slog.d(TAG, "app binder died");
 
                     removeSelf();
-                    return;
-                }
-
-                synchronized (mLock) {
-                    showResponseLocked(response, response.isAuthRequired());
-                }
+                }, 0);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "linkToDeath() on mAppCallback failed: " + e);
             }
+        }
 
-            @Override
-            public void showError(CharSequence message) {
-                // TODO(b/33197203): add MetricsLogger call
-                if (DEBUG) Slog.d(TAG, "showError(): " + message);
 
-                mUi.showError(message);
+        // FillServiceCallbacks
+        @Override
+        public void onFillRequestSuccess(FillResponse response) {
+            // TODO(b/33197203): add MetricsLogger call
+            if (response == null) {
                 removeSelf();
+                return;
             }
-
-            @Override
-            public void onSaved() {
-                // TODO(b/33197203): add MetricsLogger call
-                if (DEBUG) Slog.d(TAG, "onSaved()");
-
-                removeSelf();
+            synchronized (mLock) {
+                processResponseLocked(response);
             }
+        }
 
-            @Override
-            public void unlockFillResponse(int flags) {
-                // TODO(b/33197203): add proper MetricsLogger calls?
-                if (DEBUG) Log.d(TAG, "unlockUser(): flags=" + flags);
+        // FillServiceCallbacks
+        @Override
+        public void onFillRequestFailure(CharSequence message) {
+            // TODO(b/33197203): add MetricsLogger call
+            getUiForShowing().showError(message);
+            removeSelf();
+        }
 
-                synchronized (mLock) {
-                    if ((flags & FLAG_AUTHENTICATION_SUCCESS) != 0) {
-                        if (mResponseRequiringAuth == null) {
-                            Log.wtf(TAG, "unlockUser(): no mResponseRequiringAuth on flags "
-                                    + flags);
-                            removeSelf();
-                            return;
-                        }
-                        final List<Dataset> datasets = mResponseRequiringAuth.getDatasets();
-                        if (datasets.isEmpty()) {
-                            Log.w(TAG, "unlockUser(): no dataset on previous response: "
-                                    + mResponseRequiringAuth);
-                            removeSelf();
-                            return;
-                        }
-                        mAutoFillDirectly = true;
-                        showResponseLocked(mResponseRequiringAuth, false);
-                    }
-                    // TODO(b/33197203): show UI error on authentication failure?
-                    // Or let service handle it?
-                }
-            }
+        // FillServiceCallbacks
+        @Override
+        public void onSaveRequestSuccess() {
+            // TODO(b/33197203): add MetricsLogger call
+            // Nothing left to do...
+            removeSelf();
+        }
 
-            @Override
-            public void unlockDataset(Dataset dataset, int flags) {
-                // TODO(b/33197203): add proper MetricsLogger calls?
-                if (DEBUG) Log.d(TAG, "unlockDataset(): dataset=" + dataset + ", flags=" + flags);
+        // FillServiceCallbacks
+        @Override
+        public void onSaveRequestFailure(CharSequence message) {
+            // TODO(b/33197203): add MetricsLogger call
+            getUiForShowing().showError(message);
+            removeSelf();
+        }
 
-                if ((flags & FLAG_AUTHENTICATION_SUCCESS) != 0) {
-                    autoFillApp(dataset != null ? dataset : mDatasetRequiringAuth);
-                    return;
-                }
-            }
-        };
+        // FillServiceCallbacks
+        @Override
+        public void authenticate(IntentSender intent, Intent fillInIntent) {
+            startAuthIntent(intent, fillInIntent);
+        }
 
-        final int mId;
+        // FillServiceCallbacks
+        @Override
+        public void onServiceDied(RemoteFillService service) {
+            // TODO(b/33197203): implement
+        }
 
-        private Session(int id, IBinder activityToken) {
-            mUi = new AutoFillUI(mContext, this);
-            mId = id;
-            mActivityToken = new WeakReference<>(activityToken);
+        // AutoFillUiCallback
+        @Override
+        public void fill(Dataset dataset) {
+            autoFill(dataset);
+        }
+
+        // AutoFillUiCallback
+        @Override
+        public void save() {
+            mHandlerCaller.getHandler().obtainMessage(MSG_SERVICE_SAVE, mActivityToken)
+                    .sendToTarget();
         }
 
         /**
-         * Callback used to indivate a field has been updated.
+         * Show the save UI, when session can be saved.
          */
-        void updateValueLocked(AutoFillId id, AutoFillValue newValue) {
-          if (DEBUG) Slog.d(TAG, "updateValueLocked(): id=" + id + ", newValue=" + newValue);
-
-          // TODO(b/33197203): ignore if not part of the savable ids.
-          if (mUpdatedValues == null) {
-                // Lazy intializes it
-                mUpdatedValues = new HashMap<>();
+        public void showSaveLocked() {
+            if (mStructure == null) {
+                // Sanity check; should not happen...
+                Slog.wtf(TAG, "showSaveLocked(): no mStructure");
+                return;
             }
-            mUpdatedValues.put(id, newValue);
+            if (mCurrentResponse == null) {
+                // Happens when the activity / session was finished before the service replied.
+                Slog.d(TAG, "showSaveLocked(): no mCurrentResponse yet");
+                return;
+            }
+            final ArraySet<AutoFillId> savableIds = mCurrentResponse.getSavableIds();
+            if (VERBOSE) Slog.v(TAG, "showSaveLocked(): savableIds=" + savableIds);
+
+            if (savableIds.isEmpty()) {
+                if (DEBUG) Slog.d(TAG, "showSaveLocked(): service doesn't want to save");
+                return;
+            }
+
+            final int size = savableIds.size();
+            for (int i = 0; i < size; i++) {
+                final AutoFillId id = savableIds.valueAt(i);
+                final ViewState state = mViewStates.get(id);
+                if (state != null && state.mValueUpdated) {
+                    final AutoFillValue filledValue = findValue(mAutoFilledDataset, id);
+                    if (state.mAutoFillValue == null || state.mAutoFillValue.equals(filledValue)) {
+                        continue;
+                    }
+                    if (DEBUG) {
+                        Slog.d(TAG, "finishSessionLocked(): found a change on " + id + ": "
+                                + state.mAutoFillValue);
+                    }
+                    mUi.showSaveUi();
+                    return;
+                }
+            }
+            // Nothing changed...
+            if (DEBUG) Slog.d(TAG, "showSaveLocked(): with no changes, comes no responsibilities");
         }
 
         /**
          * Calls service when user requested save.
          */
-        void onSaveLocked() {
-            if (DEBUG) Slog.d(TAG, "onSaveLocked(): mUpdateValues=" + mUpdatedValues);
+        private void callSaveLocked() {
+            if (DEBUG) Slog.d(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
 
-            if (mStructure == null) {
-                // Sanity check; should not happen...
-                Slog.wtf(TAG, "onSaveLocked(): no mStructure");
-                return;
-            }
+            // TODO(b/33197203): hookup extras and make sure they're tested by CTS
+            final Bundle extras = null;
+//            // TODO(b/33197203): make sure the extras are tested by CTS
+//            final Bundle responseExtras = mCurrentResponse == null ? null
+//                    : mCurrentResponse.getExtras();
+//            final Bundle datasetExtras = mAutoFilledDataset == null ? null
+//                    : mAutoFilledDataset.getExtras();
+//            final Bundle extras = (responseExtras == null && datasetExtras == null)
+//                    ? null : new Bundle();
+//            if (responseExtras != null) {
+//                if (DEBUG) {
+//                    Slog.d(TAG, "response extras on save extras: "
+//                            + bundleToString(responseExtras));
+//                }
+//                extras.putBundle(AutoFillService.EXTRA_RESPONSE_EXTRAS, responseExtras);
+//            }
+//            if (datasetExtras != null) {
+//                if (DEBUG) {
+//                    Slog.d(TAG, "dataset extras on save extras: " + bundleToString(datasetExtras));
+//                }
+//                extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetExtras);
+//            }
 
-            if (mUpdatedValues == null || mUpdatedValues.isEmpty()) {
-                // Nothing changed
-                if (DEBUG) Slog.d(TAG, "onSave(): when no changes, comes no responsibilities");
 
-                return;
-            }
-
-            // TODO(b/33197203): make sure the extras are tested by CTS
-            final Bundle responseExtras = mCurrentResponse == null ? null
-                    : mCurrentResponse.getExtras();
-            final Bundle datasetExtras = mAutoFilledDataset == null ? null
-                    : mAutoFilledDataset.getExtras();
-            final Bundle extras = (responseExtras == null && datasetExtras == null)
-                    ? null : new Bundle();
-            if (responseExtras != null) {
-                if (DEBUG) {
-                    Slog.d(TAG, "response extras on save extras: "
-                            + bundleToString(responseExtras));
+            for (Entry<AutoFillId, ViewState> entry : mViewStates.entrySet()) {
+                final AutoFillValue value = entry.getValue().mAutoFillValue;
+                if (value == null) {
+                    if (VERBOSE) Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
+                    continue;
                 }
-                extras.putBundle(AutoFillService.EXTRA_RESPONSE_EXTRAS, responseExtras);
-            }
-            if (datasetExtras != null) {
-                if (DEBUG) {
-                    Slog.d(TAG, "dataset extras on save extras: " + bundleToString(datasetExtras));
-                }
-                extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetExtras);
-            }
-
-
-            for (Entry<AutoFillId, AutoFillValue> entry : mUpdatedValues.entrySet()) {
                 final AutoFillId id = entry.getKey();
                 final ViewNode node = findViewNodeByIdLocked(id);
                 if (node == null) {
-                    Slog.w(TAG, "onSaveLocked(): did not find node with id " + id);
+                    Slog.w(TAG, "callSaveLocked(): did not find node with id " + id);
                     continue;
                 }
-                final AutoFillValue value = entry.getValue();
-                if (DEBUG) Slog.d(TAG, "onSaveLocked(): updating " + id + " to " + value);
+                if (DEBUG) Slog.d(TAG, "callSaveLocked(): updating " + id + " to " + value);
+
                 node.updateAutoFillValue(value);
             }
 
@@ -891,59 +639,78 @@
                 Slog.v(TAG, "Dumping " + mStructure + " before calling service.save()");
                 mStructure.dump();
             }
-            try {
-                mService.save(mStructure, mServerCallback, extras);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Error calling save on service: " + e);
-                // TODO(b/33197203): invalidate session?
-            }
+
+            mRemoteFillService.onSaveRequest(mStructure, extras);
         }
 
-        void setAppCallbackLocked(IBinder appBinder) {
-            try {
-                appBinder.linkToDeath(() -> {
-                    if (DEBUG) Slog.d(TAG, "app callback died");
-                    // TODO(b/33197203): more cleanup here?
-                    mAppCallback = null;
-                }, 0);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "linkToDeath() failed: " + e);
-            }
-            mAppCallback = IAutoFillAppCallback.Stub.asInterface(appBinder);
-        }
+        void updateLocked(AutoFillId id, Rect bounds, AutoFillValue value, int flags) {
+            if (DEBUG) Slog.d(TAG, "updateLocked(): id=" + id + ", flags=" + flags);
 
-        void updateAutoFillInput(int flags, AutoFillId autoFillId,
-                @Nullable AutoFillValue autoFillValue, @Nullable Rect bounds) {
-            synchronized (mLock) {
-                ViewState viewState = mViewStates.get(autoFillId);
-                if (viewState == null) {
-                    viewState = new ViewState(this);
-                    mViewStates.put(autoFillId, viewState);
+            if (mAutoFilledDataset != null && (flags & FLAG_VALUE_CHANGED) == 0) {
+                // TODO(b/33197203): ignoring because we don't support partitions yet
+                if (DEBUG) Slog.d(TAG, "updateLocked(): ignoring " + flags + " after auto-filled");
+                return;
+            }
+
+            ViewState viewState = mViewStates.get(id);
+            if (viewState == null) {
+                viewState = new ViewState(id, this);
+                mViewStates.put(id, viewState);
+            }
+
+            if ((flags & FLAG_START_SESSION) != 0 ) {
+                // View is triggering auto-fill.
+                mCurrentViewState = viewState;
+                viewState.update(value, bounds);
+                return;
+            }
+
+            if ((flags & FLAG_VALUE_CHANGED) != 0 && value != null &&
+                    !value.equals(viewState.mAutoFillValue)) {
+                viewState.mValueUpdated = true;
+
+                // Must check if this update was caused by auto-filling the view, in which
+                // case we just update the value, but not the UI.
+                if (mAutoFilledDataset != null) {
+                    final AutoFillValue filledValue = findValue(mAutoFilledDataset, id);
+                    if (value.equals(filledValue)) {
+                        viewState.mAutoFillValue = value;
+                        return;
+                    }
                 }
 
-                if ((flags & FLAG_UPDATE_UI_SHOW) != 0) {
-                    // Remove the UI if the ViewState has changed.
-                    if (mCurrentViewState != viewState) {
-                        mUi.hideFillUi();
-                        mCurrentViewState = viewState;
-                    }
-
-                    // If the ViewState is ready to be displayed, onReady() will be called.
-                    viewState.update(autoFillValue, bounds);
-
-                    // TODO(b/33197203): Remove when there is a response per activity.
-                    if (mCurrentResponse != null) {
-                        viewState.setResponse(mCurrentResponse);
-                    }
-                } else if ((flags & FLAG_UPDATE_UI_HIDE) != 0) {
-                    if (mCurrentViewState == viewState) {
-                        mUi.hideFillUi();
-                        mCurrentViewState = null;
-                    }
-                } else {
-                    Slog.w(TAG, "unknown flags " + flags);
-                }
+                // Just change value, don't update the UI
+                viewState.mAutoFillValue = value;
+                return;
             }
+
+            if ((flags & FLAG_FOCUS_GAINED) != 0) {
+                // Remove the UI if the ViewState has changed.
+                if (mCurrentViewState != viewState) {
+                    mUi.hideFillUi();
+                    mCurrentViewState = viewState;
+                }
+
+                // If the ViewState is ready to be displayed, onReady() will be called.
+                viewState.update(value, bounds);
+
+                // TODO(b/33197203): Remove when there is a response per activity.
+                if (mCurrentResponse != null) {
+                    viewState.setResponse(mCurrentResponse);
+                }
+
+                return;
+            }
+
+            if ((flags & FLAG_FOCUS_LOST) != 0) {
+                if (mCurrentViewState == viewState) {
+                    mUi.hideFillUi();
+                    mCurrentViewState = null;
+                }
+                return;
+            }
+
+            Slog.w(TAG, "unknown flags " + flags);
         }
 
         @Override
@@ -957,180 +724,171 @@
                     filterText = text.toString();
                 }
             }
-            mUi.showFillUi(viewState, response.getDatasets(), bounds, filterText);
+
+            getUiForShowing().showFillUi(mActivityToken, viewState, response.getDatasets(),
+                    bounds, filterText);
         }
 
-        private void showResponseLocked(FillResponse response, boolean authRequired) {
-            if (DEBUG) Slog.d(TAG, "showResponse(directly=" + mAutoFillDirectly
-                    + ", authRequired=" + authRequired +"):" + response);
+        private void processResponseLocked(FillResponse response) {
+            if (DEBUG) Slog.d(TAG, "processResponseLocked(authRequired="
+                    + response.getAuthentication() +"):" + response);
 
-            if (mAutoFillDirectly && response != null) {
-                final List<Dataset> datasets = response.getDatasets();
-                if (datasets.size() == 1) {
-                    // User authenticated and provider returned just 1 dataset - auto-fill it now!
-                    final Dataset dataset = datasets.get(0);
-                    if (DEBUG) Slog.d(TAG, "auto-filling directly from auth: " + dataset);
+            // TODO(b/33197203): add MetricsLogger calls
 
-                    autoFillApp(dataset);
-                    return;
-                }
+            mCurrentResponse = response;
+
+            if (mCurrentResponse.getAuthentication() != null) {
+                // Handle authentication.
+                final Intent fillInIntent = createAuthFillInIntent(response.getId(), mStructure,
+                        new Bundle(), new FillCallback(new IFillCallback.Stub() {
+                            @Override
+                            public void onCancellable(ICancellationSignal cancellation) {
+                                // TODO(b/33197203): Handle cancellation
+                            }
+
+                            @Override
+                            public void onSuccess(FillResponse response) {
+                                mCurrentResponse = createAuthenticatedResponse(
+                                        mCurrentResponse, response);
+                                processResponseLocked(mCurrentResponse);
+                            }
+
+                            @Override
+                            public void onFailure(CharSequence message) {
+                                getUiForShowing().showError(message);
+                                removeSelf();
+                            }
+                        }));
+
+                 getUiForShowing().showFillResponseAuthRequest(
+                         mCurrentResponse.getAuthentication(), fillInIntent);
+                 return;
             }
 
-            if (!authRequired) {
-                // TODO(b/33197203): add MetricsLogger call
-                mCurrentResponse = response;
-                // TODO(b/33197203): Consider using mCurrentResponse, depends on partitioning design
-                if (mCurrentViewState != null) {
-                    mCurrentViewState.setResponse(mCurrentResponse);
-                }
+            final ArraySet<AutoFillId> savableIds = mCurrentResponse.getSavableIds();
+            if (savableIds == null || savableIds.isEmpty()) {
+                // NOTE: it's assuming the response has no datasets, since when a dataset is added
+                // it's view id is automatically added to savable_ids
+                if (DEBUG) Slog.d(TAG, "processResponseLocked(): nothing to do");
+
+                removeSelf();
                 return;
             }
 
-            // Handles response that requires authentication.
-            // TODO(b/33197203): add MetricsLogger call, including if fingerprint requested
-
-            mResponseRequiringAuth = response;
-            final boolean requiresFingerprint = response.hasCryptoObject();
-            if (requiresFingerprint) {
-                // TODO(b/33197203): check if fingerprint is available first and call error callback
-                // with FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE if it's not.
-                // Start scanning for the fingerprint.
-                scanFingerprint(response.getCryptoObjectOpId());
+            // TODO(b/33197203): Consider using mCurrentResponse, depends on partitioning design
+            if (mCurrentViewState != null) {
+                mCurrentViewState.setResponse(mCurrentResponse);
             }
-            // Displays the message asking the user to tap (or fingerprint) for AutoFill.
-            mUi.showFillResponseAuthenticationRequest(requiresFingerprint,
-                    response.getExtras(), response.getFlags());
         }
 
         void autoFill(Dataset dataset) {
             synchronized (mLock) {
                 // Autofill it directly...
-                if (!dataset.isAuthRequired()) {
+                if (dataset.getAuthentication() == null) {
                     autoFillApp(dataset);
                     return;
                 }
 
                 // ...or handle authentication.
-
-                mDatasetRequiringAuth = dataset;
-                final boolean requiresFingerprint = dataset.hasCryptoObject();
-                if (requiresFingerprint) {
-                    // TODO(b/33197203): check if fingerprint is available first and call error
-                    // callback with FLAG_FINGERPRINT_AUTHENTICATION_NOT_AVAILABLE if it's not.
-                    // Start scanning for the fingerprint.
-                    scanFingerprint(dataset.getCryptoObjectOpId());
-                    // Displays the message asking the user to tap (or fingerprint) for AutoFill.
-                    mUi.showDatasetFingerprintAuthenticationRequest(dataset);
-                } else {
-                    try {
-                        mService.authenticateDataset(dataset.getExtras(),
-                                FLAG_AUTHENTICATION_REQUESTED);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Error authenticating dataset: " + e);
+                Intent fillInIntent = createAuthFillInIntent(dataset.getId(), mStructure,
+                        new Bundle(), new FillCallback(new IFillCallback.Stub() {
+                    @Override
+                    public void onCancellable(ICancellationSignal cancellation) {
+                        // TODO(b/33197203): Handle cancellation
                     }
-                }
+
+                    @Override
+                    public void onSuccess(FillResponse response) {
+                        mCurrentResponse = createAuthenticatedResponse(
+                                mCurrentResponse, response);
+                        final Dataset augmentedDataset = Helper.findDatasetById(dataset.getId(),
+                                mCurrentResponse);
+                        if (augmentedDataset != null) {
+                            autoFill(augmentedDataset);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(CharSequence message) {
+                        getUiForShowing().showError(message);
+                        removeSelf();
+                    }
+                }));
+
+                startAuthIntent(dataset.getAuthentication(), fillInIntent);
+            }
+        }
+
+        private Intent createAuthFillInIntent(String itemId, AssistStructure structure,
+                Bundle extras, FillCallback fillCallback) {
+            Intent fillInIntent = new Intent();
+            fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_ITEM_ID, itemId);
+            fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_ASSIST_STRUCTURE, structure);
+            fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_EXTRAS, extras);
+            fillInIntent.putExtra(Intent.EXTRA_AUTO_FILL_CALLBACK, fillCallback);
+            return fillInIntent;
+        }
+
+        private void startAuthIntent(IntentSender intent, Intent fillInIntent) {
+            try {
+                mAppCallback.startIntentSender(intent, fillInIntent);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error launching auth intent", e);
             }
         }
 
         void dumpLocked(String prefix, PrintWriter pw) {
-            pw.print(prefix); pw.print("mId: "); pw.println(mId);
-            pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken.get());
+            pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
             pw.print(prefix); pw.print("mCurrentResponse: "); pw.println(mCurrentResponse);
-            pw.print(prefix);
-                pw.print("mResponseRequiringAuth: "); pw.println(mResponseRequiringAuth);
-            pw.print(prefix);
-                pw.print("mDatasetRequiringAuth: "); pw.println(mDatasetRequiringAuth);
-            pw.print(prefix); pw.print("mAutoFillDirectly: "); pw.println(mAutoFillDirectly);
+            pw.print(prefix); pw.print("mAutoFilledDataset: "); pw.println(mAutoFilledDataset);
             pw.print(prefix); pw.print("mCurrentViewStates: "); pw.println(mCurrentViewState);
             pw.print(prefix); pw.print("mViewStates: "); pw.println(mViewStates.size());
             final String prefix2 = prefix + "  ";
             for (Map.Entry<AutoFillId, ViewState> entry : mViewStates.entrySet()) {
-                pw.print(prefix2);
-                pw.print(entry.getKey()); pw.print(": " ); pw.println(entry.getValue());
+                pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
+                entry.getValue().dump(prefix2, pw);
             }
-            pw.print(prefix); pw.print("mUpdatedValues: "); pw.println(mUpdatedValues);
-            pw.print(prefix); pw.print("mStructure: " );
-            // TODO(b/33197203): add method do dump AssistStructure on pw
-            if (mStructure != null) {
-                pw.println("look at logcat" );
-                mStructure.dump(); // dumps to logcat
-            } else {
-                pw.println("null");
-            }
-        }
-
-        /**
-         * Notifies the result of a {@link FillResponse} authentication request to the service.
-         *
-         * <p>Typically called by the UI after user taps the "Tap to autofill" affordance, or after user
-         * used the fingerprint sensors to authenticate.
-         */
-        void notifyResponseAuthenticationResult(Bundle extras, int flags) {
-            if (DEBUG) Slog.d(TAG, "notifyResponseAuthenticationResult(): flags=" + flags
-                    + ", extras=" + bundleToString(extras));
-            synchronized (mLock) {
-                try {
-                    mService.authenticateFillResponse(extras, flags);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Error sending authentication result back to service: " + e);
+            if (VERBOSE) {
+                pw.print(prefix); pw.print("mStructure: " );
+                // TODO(b/33197203): add method do dump AssistStructure on pw
+                if (mStructure != null) {
+                    pw.println("look at logcat" );
+                    mStructure.dump(); // dumps to logcat
+                } else {
+                    pw.println("null");
                 }
             }
-        }
 
-        /**
-         * Notifies the result of a {@link Dataset} authentication request to the service.
-         *
-         * <p>Typically called by the UI after user taps the "Tap to autofill" affordance, or after
-         * it gets the results from a fingerprint authentication.
-         */
-        void notifyDatasetAuthenticationResult(Bundle extras, int flags) {
-            if (DEBUG) Slog.d(TAG, "notifyDatasetAuthenticationResult(): flags=" + flags
-                    + ", extras=" + bundleToString(extras));
-            synchronized (mLock) {
-                try {
-                    mService.authenticateDataset(extras, flags);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Error sending authentication result back to service: " + e);
-                }
-            }
+            mRemoteFillService.dump(prefix, pw);
         }
 
         void autoFillApp(Dataset dataset) {
             synchronized (mLock) {
                 try {
                     if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+
                     mAppCallback.autoFill(dataset);
+                    mAutoFilledDataset = dataset;
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Error auto-filling activity: " + e);
                 }
             }
         }
 
-        /**
-         * Called by UI to trigger a save request to the service.
-         */
-        void requestSave() {
-            synchronized (mLock) {
-                onSaveLocked();
+        void enableSessionLocked() {
+            if (DEBUG) Slog.d(TAG, "enableSessionLocked()");
+
+            try {
+                mAppCallback.enableSession();
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Error enabling session: " + e);
             }
         }
 
-        private void scanFingerprint(long opId) {
-            // TODO(b/33197203): add MetricsLogger call
-            if (DEBUG) Slog.d(TAG, "Starting fingerprint scan for op id: " + opId);
-
-            // TODO(b/33197203): since we're clearing the AutoFillService's identity, make sure
-            // this method is only called at the proper times, otherwise a malicious provider could
-            // keep the callback refence to bypass the check
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // TODO(b/33197203): set a timeout?
-                mFingerprintService.authenticate(mAuthToken, opId, mUserId, mServiceReceiver, 0,
-                        null);
-            } catch (RemoteException e) {
-                // Local call, shouldn't happen.
-            } finally {
-                Binder.restoreCallingIdentity(token);
+        private AutoFillUI getUiForShowing() {
+            synchronized (mLock) {
+                mUi.setCallbackLocked(this, mActivityToken);
+                return mUi;
             }
         }
 
@@ -1167,10 +925,95 @@
             return null;
         }
 
+        private void destroyLocked() {
+            mRemoteFillService.destroy();
+            mUi.hideAll();
+            mUi.setCallbackLocked(null, null);
+        }
+
         private void removeSelf() {
+            if (VERBOSE) Slog.v(TAG, "removeSelf()");
+
             synchronized (mLock) {
-                removeSessionLocked(mId);
+                destroyLocked();
+                mSessions.remove(mActivityToken);
             }
         }
+
+        /**
+         * Creates a response from the {@code original} and an {@code update} by
+         * replacing all items that needed authentication (response or datasets)
+         * with their updated version if the latter does not need authentication.
+         * New datasets that don't require auth are appended.
+         *
+         * @param original The original response requiring auth at some level.
+         * @param update An updated response with auth not needed anymore at some level.
+         * @return A new response with updated items where auth is not needed anymore.
+         */
+        // TODO(b/33197203) Unit test
+        FillResponse createAuthenticatedResponse(FillResponse original, FillResponse update) {
+            // Can update only if ids match
+            if (!original.getId().equals(update.getId())) {
+                return original;
+            }
+
+            // If the original required auth and the update doesn't, the update wins
+            // but only if none of the update's datasets requires authentication.
+            if (original.getAuthentication() != null && update.getAuthentication() == null) {
+                ArraySet<Dataset> updateDatasets = update.getDatasets();
+                final int udpateDatasetCount = updateDatasets.size();
+                for (int i = 0; i < udpateDatasetCount; i++) {
+                    Dataset updateDataset = updateDatasets.valueAt(i);
+                    if (updateDataset.getAuthentication() != null) {
+                        return original;
+                    }
+                }
+                return update;
+            }
+
+            // If no auth on response level we create a response that has all
+            // datasets from the original with the ones that required auth but
+            // not anymore updated and new ones not requiring auth appended.
+
+            // The update shouldn't require auth
+            if (update.getAuthentication() != null) {
+                return original;
+            }
+
+            final FillResponse.Builder builder = new FillResponse.Builder(original.getId());
+
+            // Update existing datasets
+            final ArraySet<Dataset> origDatasets = original.getDatasets();
+            final int origDatasetCount = origDatasets.size();
+            for (int i = 0; i < origDatasetCount; i++) {
+                Dataset origDataset = origDatasets.valueAt(i);
+                ArraySet<Dataset> updateDatasets = update.getDatasets();
+                final int updateDatasetCount = updateDatasets.size();
+                for (int j = 0; j < updateDatasetCount; j++) {
+                    Dataset updateDataset = updateDatasets.valueAt(j);
+                    if (origDataset.getId().equals(updateDataset.getId())) {
+                        // The update shouldn't require auth
+                        if (updateDataset.getAuthentication() == null) {
+                            origDataset = updateDataset;
+                            updateDatasets.removeAt(j);
+                        }
+                        break;
+                    }
+                }
+                builder.addDataset(origDataset);
+            }
+
+            // Add new datasets
+            final ArraySet<Dataset> updateDatasets = update.getDatasets();
+            final int updateDatasetCount = updateDatasets.size();
+            for (int i = 0; i < updateDatasetCount; i++) {
+                final Dataset updateDataset = updateDatasets.valueAt(i);
+                builder.addDataset(updateDataset);
+            }
+
+            // For now no extras and savable id updates.
+
+            return builder.build();
+        }
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
index 5c6009a..201a889 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -40,8 +40,6 @@
         final PrintWriter pw = getOutPrintWriter();
         try {
             switch (cmd) {
-                case "fill":
-                    return requestAutoFill();
                 case "save":
                     return requestSave();
                 default:
@@ -60,20 +58,12 @@
             pw.println("  help");
             pw.println("    Prints this help text.");
             pw.println("");
-            pw.println("  fill [--user USER_ID]");
-            pw.println("    Request provider to auto-fill the top activity. ");
             pw.println("  save [--user USER_ID]");
             pw.println("    Request provider to save contents of the top activity. ");
             pw.println("");
         }
     }
 
-    private int requestAutoFill() throws RemoteException {
-        final int userId = getUserIdFromArgs();
-        mService.requestAutoFillForUser(userId);
-        return 0;
-    }
-
     private int requestSave() throws RemoteException {
         final int userId = getUserIdFromArgs();
         mService.requestSaveForUser(userId);
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
index 76c2916..0763c74 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
@@ -15,13 +15,10 @@
  */
 package com.android.server.autofill;
 
-
 import static com.android.server.autofill.Helper.DEBUG;
 
 import android.annotation.Nullable;
-import android.app.Activity;
 import android.app.Notification;
-import android.app.Notification.Action;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -29,12 +26,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.graphics.Rect;
-import android.graphics.PixelFormat;
 import android.os.Binder;
-import android.os.Bundle;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.os.Looper;
+import android.text.format.DateUtils;
 import android.util.Slog;
-import android.view.autofill.AutoFillId;
 import android.view.autofill.Dataset;
 import android.view.autofill.FillResponse;
 import android.view.Gravity;
@@ -44,49 +43,77 @@
 import android.view.WindowManager.LayoutParams;
 import android.widget.Toast;
 
-import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.HandlerCaller;
 import com.android.server.UiThread;
-import com.android.server.autofill.AutoFillManagerServiceImpl.Session;
 import com.android.server.autofill.AutoFillManagerServiceImpl.ViewState;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.List;
 
 /**
  * Handles all auto-fill related UI tasks.
  */
 // TODO(b/33197203): document exactly what once the auto-fill bar is implemented
 final class AutoFillUI {
-
     private static final String TAG = "AutoFillUI";
+    private static final long SNACK_BAR_LIFETIME_MS = 30 * DateUtils.SECOND_IN_MILLIS;
+    private static final int MSG_HIDE_SNACK_BAR = 1;
+
+    private static final String EXTRA_AUTH_INTENT_SENDER =
+            "com.android.server.autofill.extra.AUTH_INTENT_SENDER";
+    private static final String EXTRA_AUTH_FILL_IN_INTENT =
+            "com.android.server.autofill.extra.AUTH_FILL_IN_INTENT";
 
     private final Context mContext;
-    private final Session mSession;
     private final WindowManager mWm;
 
+    // TODO(b/33197203) Fix locking - some state requires lock and some not - requires refactoring
+
     // Fill UI variables
     private AnchoredWindow mFillWindow;
     private DatasetPicker mFillView;
     private ViewState mViewState;
-    private Rect mBounds;
-    private String mFilterText;
+
+    private AutoFillUiCallback mCallback;
+    private IBinder mActivityToken;
+
+    private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
+        switch (msg.what) {
+            case MSG_HIDE_SNACK_BAR: {
+                hideSnackbarUiThread();
+                return;
+            }
+            default: {
+                Slog.w(TAG, "Invalid message: " + msg);
+            }
+        }
+    };
+    private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(),
+            mHandlerCallback, true);
 
     /**
      * Custom snackbar UI used for saving autofill or other informational messages.
      */
     private View mSnackbar;
 
-    AutoFillUI(Context context, Session session) {
+    AutoFillUI(Context context) {
         mContext = context;
-        mSession = session;
         mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     }
 
+    void setCallbackLocked(AutoFillUiCallback callback, IBinder activityToken) {
+        hideAll();
+        mCallback = callback;
+        mActivityToken = activityToken;
+    }
+
     /**
      * Displays an error message to the user.
      */
     void showError(CharSequence message) {
+        if (!hasCallback()) {
+            return;
+        }
+        hideAll();
         // TODO(b/33197203): proper implementation
         UiThread.getHandler().runWithScissors(() -> {
             Toast.makeText(mContext, "AutoFill error: " + message, Toast.LENGTH_LONG).show();
@@ -95,71 +122,80 @@
 
     /**
      * Hides the fill UI.
-     * Shows the options from a {@link FillResponse} so the user can pick up the proper
-     * {@link Dataset} (when the response has one) for a given view (identified by
-     * {@code autoFillId}).
      */
     void hideFillUi() {
         UiThread.getHandler().runWithScissors(() -> {
-            hideFillUiLocked();
+            hideFillUiUiThread();
         }, 0);
     }
 
-    // Must be called in inside UI Thread
-    private void hideFillUiLocked() {
+    @android.annotation.UiThread
+    private void hideFillUiUiThread() {
         if (mFillWindow != null) {
-            if (DEBUG) Slog.d(TAG, "hideFillUiLocked(): hide" + mFillWindow);
-
+            if (DEBUG) Slog.d(TAG, "hideFillUiUiThread(): hide" + mFillWindow);
             mFillWindow.hide();
         }
 
         mViewState = null;
-        mBounds = null;
-        mFilterText = null;
         mFillView = null;
         mFillWindow = null;
     }
 
-
     /**
      * Shows the fill UI, removing the previous fill UI if the has changed.
      *
+     * @param appToken the token of the app to be autofilled
      * @param viewState the view state, compared by reference to know if new UI should be shown
      * @param datasets the datasets to show, not used if viewState is the same
      * @param bounds bounds of the view to be filled, used if changed
      * @param filterText text of the view to be filled, used if changed
      */
-    void showFillUi(ViewState viewState, List<Dataset> datasets, Rect bounds,
-            String filterText) {
+    void showFillUi(IBinder appToken, ViewState viewState, @Nullable ArraySet<Dataset> datasets,
+            Rect bounds, String filterText) {
+        if (!hasCallback()) {
+            return;
+        }
+
         UiThread.getHandler().runWithScissors(() -> {
-            if (mViewState != viewState) {
-                // new
-                hideFillUi();
+            hideSnackbarUiThread();
+            hideFillResponseAuthUiUiThread();
+        }, 0);
+
+        if (datasets == null) {
+            // TODO(b/33197203): shouldn't be called, but keeping the WTF for a while just to be
+            // safe, otherwise it would crash system server...
+            Slog.wtf(TAG, "showFillUI(): no dataset");
+            return;
+        }
+
+        UiThread.getHandler().runWithScissors(() -> {
+            if (mViewState == null || !mViewState.mId.equals(viewState.mId)) {
+                hideFillUiUiThread();
 
                 mViewState = viewState;
 
                 mFillView = new DatasetPicker(mContext, datasets,
                         (dataset) -> {
-                            mSession.autoFillApp(dataset);
+                            final AutoFillUiCallback callback;
+                            synchronized (mLock) {
+                                callback = mCallback;
+                            }
+                            if (callback != null) {
+                                callback.fill(dataset);
+                            } else {
+                                Slog.w(TAG, "null callback on showFillUi() for " + viewState.mId);
+                            }
                             hideFillUi();
                         });
-                mFillWindow = new AnchoredWindow(
-                        mWm, mFillView, 800, ViewGroup.LayoutParams.WRAP_CONTENT);
 
-                if (DEBUG) Slog.d(TAG, "show FillUi");
+                mFillWindow = new AnchoredWindow(mWm, appToken, mFillView);
+
+                if (DEBUG) Slog.d(TAG, "showFillUi(): view changed");
             }
 
-            if (!bounds.equals(mBounds)) {
-                if (DEBUG) Slog.d(TAG, "update FillUi bounds: " + mBounds);
-                mBounds = bounds;
-                mFillWindow.show(mBounds);
-            }
-
-            if (!filterText.equals(mFilterText)) {
-                if (DEBUG) Slog.d(TAG, "update FillUi filter text: " + mFilterText);
-                mFilterText = filterText;
-                mFillView.update(mFilterText);
-            }
+            if (DEBUG) Slog.d(TAG, "showFillUi(): bounds=" + bounds + ", filterText=" + filterText);
+            mFillView.update(filterText);
+            mFillWindow.show(bounds);
         }, 0);
     }
 
@@ -170,27 +206,14 @@
      * <p>It typically replaces the auto-fill bar with a message saying "Press fingerprint or tap to
      * autofill" or "Tap to autofill", depending on the value of {@code usesFingerprint}.
      */
-    void showFillResponseAuthenticationRequest(boolean usesFingerprint,
-            Bundle extras, int flags) {
-        // TODO(b/33197203): proper implementation
-        showAuthNotification(usesFingerprint, extras, flags);
-    }
-
-    /**
-     * Shows an UI affordance asking indicating that user action is required before a
-     * {@link Dataset} can be used.
-     *
-     * <p>It typically replaces the auto-fill bar with a message saying "Press fingerprint to
-     * autofill".
-     */
-    void showDatasetFingerprintAuthenticationRequest(Dataset dataset) {
-        if (DEBUG) Slog.d(TAG, "showDatasetAuthenticationRequest(): dataset=" + dataset);
-
-        // TODO(b/33197203): proper implementation (either pop up a fingerprint dialog or replace
-        // the auto-fill bar with a new message.
+    void showFillResponseAuthRequest(IntentSender intent, Intent fillInIntent) {
+        if (!hasCallback()) {
+            return;
+        }
+        hideAll();
         UiThread.getHandler().runWithScissors(() -> {
-            Toast.makeText(mContext, "AutoFill: press fingerprint to unlock " + dataset.getName(),
-                    Toast.LENGTH_LONG).show();
+            // TODO(b/33197203): proper implementation
+            showFillResponseAuthUiUiThread(intent, fillInIntent);
         }, 0);
     }
 
@@ -198,46 +221,37 @@
      * Shows the UI asking the user to save for auto-fill.
      */
     void showSaveUi() {
-        showSnackbar(new SavePrompt(mContext, new SavePrompt.OnSaveListener() {
-            @Override
-            public void onSaveClick() {
-                hideSnackbar();
-
-                // TODO(b/33197203): add MetricsLogger call
-                mSession.requestSave();
-            }
-            @Override
-            public void onCancelClick() {
-                hideSnackbar();
-            }
-        }));
-    }
-
-    /**
-     * Called by service after the user user the fingerprint sensors to authenticate.
-     */
-    void dismissFingerprintRequest(boolean success) {
-        if (DEBUG) Slog.d(TAG, "dismissFingerprintRequest(): ok=" + success);
-
-        dismissAuthNotification();
-
-        if (!success) {
-            // TODO(b/33197203): proper implementation (snack bar / i18n string)
-            UiThread.getHandler().runWithScissors(() -> {
-                Toast.makeText(mContext, "AutoFill: fingerprint failed", Toast.LENGTH_LONG).show();
-            }, 0);
+        if (!hasCallback()) {
+            return;
         }
+        hideAll();
+        UiThread.getHandler().runWithScissors(() -> {
+            showSnackbarUiThread(new SavePrompt(mContext,
+                    new SavePrompt.OnSaveListener() {
+                @Override
+                public void onSaveClick() {
+                    hideSnackbarUiThread();
+                    // TODO(b/33197203): add MetricsLogger call
+                    mCallback.save();
+                }
+
+                @Override
+                public void onCancelClick() {
+                    // TODO(b/33197203): add MetricsLogger call
+                    hideSnackbarUiThread();
+                }
+            }));
+        }, 0);
     }
 
     /**
-     * Closes all UI affordances.
+     * Hides all UI affordances.
      */
-    void closeAll() {
-        if (DEBUG) Slog.d(TAG, "closeAll()");
-
+    void hideAll() {
         UiThread.getHandler().runWithScissors(() -> {
-            hideSnackbarLocked();
-            hideFillUiLocked();
+            hideSnackbarUiThread();
+            hideFillUiUiThread();
+            hideFillResponseAuthUiUiThread();
         }, 0);
     }
 
@@ -245,16 +259,14 @@
         pw.println("AufoFill UI");
         final String prefix = "  ";
         pw.print(prefix); pw.print("sResultCode: "); pw.println(sResultCode);
-        pw.print(prefix); pw.print("mSessionId: "); pw.println(mSession.mId);
+        pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
         pw.print(prefix); pw.print("mSnackBar: "); pw.println(mSnackbar);
         pw.print(prefix); pw.print("mViewState: "); pw.println(mViewState);
-        pw.print(prefix); pw.print("mBounds: "); pw.println(mBounds);
-        pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText);
     }
 
     //similar to a snackbar, but can be a bit custom since it is more than just text. This will
     //allow two buttons for saving or not saving the autofill for instance as well.
-    private void showSnackbar(View snackBar) {
+    private void showSnackbarUiThread(View snackBar) {
         final LayoutParams params = new LayoutParams();
         params.setTitle("AutoFill Save");
         params.type = LayoutParams.TYPE_PHONE; // TODO(b/33197203) use app window token
@@ -272,22 +284,34 @@
             mSnackbar = snackBar;
             mWm.addView(mSnackbar, params);
         }, 0);
+
+        if (DEBUG) {
+            Slog.d(TAG, "showSnackbar(): auto dismissing it in " + SNACK_BAR_LIFETIME_MS + " ms");
+        }
+        mHandlerCaller.sendMessageDelayed(mHandlerCaller.obtainMessage(MSG_HIDE_SNACK_BAR),
+                SNACK_BAR_LIFETIME_MS);
     }
 
-    private void hideSnackbar() {
-        UiThread.getHandler().runWithScissors(() -> {
-            hideSnackbarLocked();
-        }, 0);
-    }
-
-    // Must be called in inside UI Thread
-    private void hideSnackbarLocked() {
+    private void hideSnackbarUiThread() {
+        mHandlerCaller.getHandler().removeMessages(MSG_HIDE_SNACK_BAR);
         if (mSnackbar != null) {
             mWm.removeView(mSnackbar);
             mSnackbar = null;
         }
     }
 
+    private boolean hasCallback() {
+        synchronized (mLock) {
+            return mCallback != null;
+        }
+    }
+
+    interface AutoFillUiCallback {
+        void authenticate(IntentSender intent, Intent fillInIntent);
+        void fill(Dataset dataset);
+        void save();
+    }
+
     /////////////////////////////////////////////////////////////////////////////////
     // TODO(b/33197203): temporary code using a notification to request auto-fill. //
     // Will be removed once UX decide the right way to present it to the user.     //
@@ -297,25 +321,13 @@
     private static final String NOTIFICATION_AUTO_FILL_INTENT =
             "com.android.internal.autofill.action.REQUEST_AUTOFILL";
 
-    // Extras used in the notification intents
-    private static final String EXTRA_USER_ID = "user_id";
-    private static final String EXTRA_NOTIFICATION_TYPE = "notification_type";
-    private static final String EXTRA_SESSION_ID = "session_id";
-    private static final String EXTRA_FILL_RESPONSE = "fill_response";
-    private static final String EXTRA_DATASET = "dataset";
-    private static final String EXTRA_AUTH_REQUIRED_EXTRAS = "auth_required_extras";
-    private static final String EXTRA_FLAGS = "flags";
-
-    private static final String TYPE_OPTIONS = "options";
-    private static final String TYPE_AUTH_RESPONSE = "auth_response";
-
     private BroadcastReceiver mNotificationReceiver;
     private final Object mLock = new Object();
 
     // Hack used to generate unique pending intents
     static int sResultCode = 0;
 
-    private void setNotificationListener() {
+    private void ensureNotificationListener() {
         synchronized (mLock) {
             if (mNotificationReceiver == null) {
                 mNotificationReceiver = new NotificationReceiver();
@@ -328,83 +340,58 @@
     final class NotificationReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            final String type = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
-            if (type == null) {
-                Slog.wtf(TAG, "No extra " + EXTRA_NOTIFICATION_TYPE + " on intent " + intent);
-                return;
-            }
-            final Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET);
-            final int flags = intent.getIntExtra(EXTRA_FLAGS, 0);
-
-            if (DEBUG) Slog.d(TAG, "Notification received: type=" + type
-                    + ", sessionId=" + mSession.mId);
+            final AutoFillUiCallback callback;
             synchronized (mLock) {
-                switch (type) {
-                    case TYPE_AUTH_RESPONSE:
-                        mSession.notifyResponseAuthenticationResult(
-                                intent.getBundleExtra(EXTRA_AUTH_REQUIRED_EXTRAS), flags);
-                        break;
-                    default: {
-                        Slog.w(TAG, "Unknown notification type: " + type);
-                    }
-                }
+                callback = mCallback;
+            }
+            if (callback != null) {
+                IntentSender intentSender = intent.getParcelableExtra(EXTRA_AUTH_INTENT_SENDER);
+                Intent fillInIntent = intent.getParcelableExtra(EXTRA_AUTH_FILL_IN_INTENT);
+                callback.authenticate(intentSender, fillInIntent);
             }
             collapseStatusBar();
         }
     }
 
-    private static Intent newNotificationIntent(String type) {
-        final Intent intent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
-        intent.putExtra(EXTRA_NOTIFICATION_TYPE, type);
-        return intent;
-    }
-
-    private void showAuthNotification(boolean usesFingerprint,
-            Bundle extras, int flags) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            showAuthNotificationAsSystem(usesFingerprint, extras, flags);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private void showAuthNotificationAsSystem(
-            boolean usesFingerprint, Bundle extras, int flags) {
+    @android.annotation.UiThread
+    private void showFillResponseAuthUiUiThread(IntentSender intent, Intent fillInIntent) {
         final String title = "AutoFill Authentication";
         final StringBuilder subTitle = new StringBuilder("Provider require user authentication.\n");
 
-        final Intent authIntent = newNotificationIntent(TYPE_AUTH_RESPONSE);
-        if (extras != null) {
-            authIntent.putExtra(EXTRA_AUTH_REQUIRED_EXTRAS, extras);
-        }
-        if (flags != 0) {
-            authIntent.putExtra(EXTRA_FLAGS, flags);
-        }
-        final PendingIntent authPendingIntent = PendingIntent.getBroadcast(mContext, ++sResultCode,
-                authIntent, PendingIntent.FLAG_ONE_SHOT);
+        final Intent authIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
+        authIntent.putExtra(EXTRA_AUTH_INTENT_SENDER, intent);
+        authIntent.putExtra(EXTRA_AUTH_FILL_IN_INTENT, fillInIntent);
 
-        if (usesFingerprint) {
-            subTitle.append("But kindly accepts your fingerprint instead"
-                    + "\n(tap fingerprint sensor to trigger it)");
+        final PendingIntent authPendingIntent = PendingIntent.getBroadcast(
+                mContext, ++sResultCode, authIntent, PendingIntent.FLAG_ONE_SHOT);
 
-        } else {
-            subTitle.append("Tap notification to launch its authentication UI.");
-        }
+        subTitle.append("Tap notification to launch its authentication UI.");
 
         final Notification.Builder notification = newNotificationBuilder()
                 .setAutoCancel(true)
                 .setOngoing(false)
                 .setContentTitle(title)
-                .setStyle(new Notification.BigTextStyle().bigText(subTitle.toString()));
-        if (authPendingIntent != null) {
-            notification.setContentIntent(authPendingIntent);
+                .setStyle(new Notification.BigTextStyle().bigText(subTitle.toString()))
+                .setContentIntent(authPendingIntent);
+
+        ensureNotificationListener();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            NotificationManager.from(mContext).notify(0, notification.build());
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
-        NotificationManager.from(mContext).notify(mSession.mId, notification.build());
     }
 
-    private void dismissAuthNotification() {
-        NotificationManager.from(mContext).cancel(mSession.mId);
+    @android.annotation.UiThread
+    private void hideFillResponseAuthUiUiThread() {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            NotificationManager.from(mContext).cancel(0);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     private Notification.Builder newNotificationBuilder() {
diff --git a/services/autofill/java/com/android/server/autofill/DatasetPicker.java b/services/autofill/java/com/android/server/autofill/DatasetPicker.java
index 7245aaa..9bee61a 100644
--- a/services/autofill/java/com/android/server/autofill/DatasetPicker.java
+++ b/services/autofill/java/com/android/server/autofill/DatasetPicker.java
@@ -17,6 +17,8 @@
 
 import android.content.Context;
 import android.graphics.Color;
+import android.text.TextUtils;
+import android.util.ArraySet;
 import android.view.autofill.Dataset;
 import android.view.View;
 import android.view.ViewGroup;
@@ -38,15 +40,13 @@
  * 3) the View is detached.
  */
 final class DatasetPicker extends ListView implements OnItemClickListener {
-    private static final String TAG = "DatasetPicker";
-
     interface Listener {
         void onDatasetPicked(Dataset dataset);
     }
 
     private final Listener mListener;
 
-    DatasetPicker(Context context, List<Dataset> datasets, Listener listener) {
+    DatasetPicker(Context context, ArraySet<Dataset> datasets, Listener listener) {
         super(context);
         mListener = listener;
 
@@ -63,8 +63,10 @@
             @Override
             public View getView(int position, View convertView, ViewGroup parent) {
                 final TextView textView = (TextView) super.getView(position, convertView, parent);
+                textView.setSingleLine();
+                textView.setEllipsize(TextUtils.TruncateAt.END);
                 textView.setMinHeight(
-                    getDimen(com.android.internal.R.dimen.autofill_fill_item_height));
+                        getDimen(com.android.internal.R.dimen.autofill_fill_item_height));
                 return textView;
             }
         };
@@ -80,7 +82,7 @@
         adapter.getFilter().filter(prefix, new FilterListener() {
             @Override
             public void onFilterComplete(int count) {
-                DatasetPicker.this.requestLayout();
+                setVisibility(count > 0 ? View.VISIBLE : View.GONE);
             }
         });
     }
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 9171dac..0f2bb60 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -16,8 +16,15 @@
 
 package com.android.server.autofill;
 
+import android.annotation.Nullable;
 import android.os.Bundle;
+import android.util.ArraySet;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
+import android.view.autofill.Dataset;
+import android.view.autofill.FillResponse;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Objects;
 import java.util.Set;
@@ -31,7 +38,7 @@
     static void append(StringBuilder builder, Bundle bundle) {
         if (bundle == null) {
             builder.append("N/A");
-        } else if (!DEBUG) {
+        } else if (!VERBOSE) {
             builder.append(REDACTED);
         } else {
             final Set<String> keySet = bundle.keySet();
@@ -52,6 +59,46 @@
         return builder.toString();
     }
 
+    /**
+     * Gets the value of a {@link Dataset} field by its id, or {@code null} if not found.
+     */
+    @Nullable
+    static AutoFillValue findValue(Dataset dataset, AutoFillId id) {
+        if (dataset != null) {
+            final ArrayList<AutoFillId> ids = dataset.getFieldIds();
+            final int size = ids.size();
+            for (int i = 0; i < size; i++) {
+                if (id.equals(ids.get(i))) {
+                    return dataset.getFieldValues().get(i);
+                }
+
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds a data set by id in a response.
+     *
+     * @param id The dataset id.
+     * @param response The response to search.
+     * @return The dataset if found or null.
+     */
+    static Dataset findDatasetById(String id, FillResponse response) {
+        ArraySet<Dataset> datasets = response.getDatasets();
+        if (datasets == null || datasets.isEmpty()) {
+            return null;
+        }
+        final int datasetCount = datasets.size();
+        for (int i = 0; i < datasetCount; i++) {
+            Dataset dataset = datasets.valueAt(i);
+            if (dataset.getId().equals(id)) {
+                return dataset;
+            }
+        }
+        return null;
+    }
+
     private Helper() {
         throw new UnsupportedOperationException("contains static members only");
     }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
new file mode 100644
index 0000000..c070f77
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -0,0 +1,521 @@
+/*
+ * 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.server.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.assist.AssistStructure;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.ICancellationSignal;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.IAutoFillService;
+import android.service.autofill.IFillCallback;
+import android.service.autofill.ISaveCallback;
+import android.text.format.DateUtils;
+import android.util.Slog;
+import android.view.autofill.FillResponse;
+import com.android.internal.os.HandlerCaller;
+import com.android.server.FgThread;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * This class represents a remote fill service. It abstracts away the binding
+ * and unbinding from the remote implementation.
+ *
+ * <p>Clients can call methods of this class without worrying about when and
+ * how to bind/unbind/timeout. All state of this class is modified on a handler
+ * thread.
+ */
+final class RemoteFillService implements DeathRecipient {
+    private static final String LOG_TAG = "RemoteFillService";
+
+    private static final boolean DEBUG = Helper.DEBUG;
+
+    // How long after the last interaction with the service we would unbind
+    private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.MINUTE_IN_MILLIS;
+
+    private final Context mContext;
+
+    private final ComponentName mComponentName;
+
+    private final Intent mIntent;
+
+    private final FillServiceCallbacks mCallbacks;
+
+    private final int mUserId;
+
+    private final ServiceConnection mServiceConnection = new RemoteServiceConnection();
+
+    private final HandlerCaller mHandler;
+
+    private IAutoFillService mAutoFillService;
+
+    private boolean mBinding;
+
+    private boolean mDestroyed;
+
+    private boolean mServiceDied;
+
+    private boolean mCompleted;
+
+    private PendingRequest mPendingRequest;
+
+    public interface FillServiceCallbacks {
+        void onFillRequestSuccess(FillResponse response);
+        void onFillRequestFailure(CharSequence message);
+        void onSaveRequestSuccess();
+        void onSaveRequestFailure(CharSequence message);
+        void onServiceDied(RemoteFillService service);
+    }
+
+    public RemoteFillService(Context context, ComponentName componentName,
+            int userId, FillServiceCallbacks callbacks) {
+        mContext = context;
+        mCallbacks = callbacks;
+        mComponentName = componentName;
+        mIntent = new Intent(AutoFillService.SERVICE_INTERFACE)
+                .setComponent(mComponentName);
+        mUserId = userId;
+        mHandler = new MyHandler(context);
+    }
+
+    public void destroy() {
+        mHandler.obtainMessage(MyHandler.MSG_DESTROY).sendToTarget();
+    }
+
+    private void handleDestroy() {
+        if (mPendingRequest != null) {
+            mPendingRequest.cancel();
+            mPendingRequest = null;
+        }
+        ensureUnbound();
+        mDestroyed = true;
+    }
+
+    @Override
+    public void binderDied() {
+        mHandler.obtainMessage(MyHandler.MSG_BINDER_DIED).sendToTarget();
+    }
+
+    private void handleBinderDied() {
+        if (mAutoFillService != null) {
+            mAutoFillService.asBinder().unlinkToDeath(this, 0);
+        }
+        mAutoFillService = null;
+        mServiceDied = true;
+        mCallbacks.onServiceDied(this);
+    }
+
+    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+        cancelScheduledUnbind();
+        PendingFillRequest request = new PendingFillRequest(structure, extras, this);
+        mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
+    }
+
+    public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+        cancelScheduledUnbind();
+        PendingSaveRequest request = new PendingSaveRequest(structure, extras, this);
+        mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
+    }
+
+    // Note: we are dumping without a lock held so this is a bit racy but
+    // adding a lock to a class that offloads to a handler thread would
+    // mean adding a lock adding overhead to normal runtime operation.
+    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        String tab = "  ";
+        pw.append(prefix).append("service:").println();
+        pw.append(prefix).append(tab).append("userId=")
+                .append(String.valueOf(mUserId)).println();
+        pw.append(prefix).append(tab).append("componentName=")
+                .append(mComponentName.flattenToString()).println();
+        pw.append(prefix).append(tab).append("destroyed=")
+                .append(String.valueOf(mDestroyed)).println();
+        pw.append(prefix).append(tab).append("bound=")
+                .append(String.valueOf(isBound())).println();
+        pw.append(prefix).append(tab).append("hasPendingRequest=")
+                .append(String.valueOf(mPendingRequest != null)).println();
+        pw.println();
+    }
+
+    private void cancelScheduledUnbind() {
+        mHandler.removeMessages(MyHandler.MSG_UNBIND);
+    }
+
+    private void scheduleUnbind() {
+        cancelScheduledUnbind();
+        Message message = mHandler.obtainMessage(MyHandler.MSG_UNBIND);
+        mHandler.sendMessageDelayed(message, TIMEOUT_IDLE_BIND_MILLIS);
+    }
+
+    private void handleUnbind() {
+        ensureUnbound();
+    }
+
+    private void handlePendingRequest(PendingRequest pendingRequest) {
+        if (mDestroyed || mCompleted) {
+            return;
+        }
+        if (pendingRequest.isFinal()) {
+            mCompleted = true;
+        }
+        if (!isBound()) {
+            if (mPendingRequest != null) {
+                mPendingRequest.cancel();
+            }
+            mPendingRequest = pendingRequest;
+            ensureBound();
+        } else {
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "[user: " + mUserId + "] handleOnFillRequest()");
+            }
+            pendingRequest.run();
+        }
+    }
+
+    private boolean isBound() {
+        return mAutoFillService != null;
+    }
+
+    private void ensureBound() {
+        if (isBound() || mBinding) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
+        }
+        mBinding = true;
+
+        boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                new UserHandle(mUserId));
+
+        if (!willBind) {
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent);
+            }
+            mBinding = false;
+
+            if (!mServiceDied) {
+                handleBinderDied();
+            }
+        }
+    }
+
+    private void ensureUnbound() {
+        if (!isBound() && !mBinding) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.d(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
+        }
+        mBinding = false;
+        if (isBound()) {
+            mAutoFillService.asBinder().unlinkToDeath(this, 0);
+            mAutoFillService = null;
+        }
+        mContext.unbindService(mServiceConnection);
+    }
+
+    private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest,
+            FillResponse response) {
+        mHandler.getHandler().post(() -> {
+            if (handleResponseCallbackCommon(pendingRequest)) {
+                mCallbacks.onFillRequestSuccess(response);
+            }
+        });
+    }
+
+    private void dispatchOnFillRequestFailure(PendingRequest pendingRequest,
+            CharSequence message) {
+        mHandler.getHandler().post(() -> {
+            if (handleResponseCallbackCommon(pendingRequest)) {
+                mCallbacks.onFillRequestFailure(message);
+            }
+        });
+    }
+
+    private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
+        mHandler.getHandler().post(() -> {
+            if (handleResponseCallbackCommon(pendingRequest)) {
+                mCallbacks.onSaveRequestSuccess();
+            }
+        });
+    }
+
+    private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest,
+            CharSequence message) {
+        mHandler.getHandler().post(() -> {
+            if (handleResponseCallbackCommon(pendingRequest)) {
+                mCallbacks.onSaveRequestFailure(message);
+            }
+        });
+    }
+
+    private boolean handleResponseCallbackCommon(PendingRequest pendingRequest) {
+        if (mDestroyed) {
+            return false;
+        }
+        if (mPendingRequest == pendingRequest) {
+            mPendingRequest = null;
+        }
+        if (mPendingRequest == null) {
+            scheduleUnbind();
+        }
+        return true;
+    }
+
+    private class RemoteServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (mDestroyed || !mBinding) {
+                mContext.unbindService(mServiceConnection);
+                return;
+            }
+            mBinding = false;
+            mAutoFillService = IAutoFillService.Stub.asInterface(service);
+            try {
+                service.linkToDeath(RemoteFillService.this, 0);
+            } catch (RemoteException re) {
+                handleBinderDied();
+                return;
+            }
+
+            if (mPendingRequest != null) {
+                handlePendingRequest(mPendingRequest);
+            }
+
+            mServiceDied = false;
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mBinding = true;
+            mAutoFillService = null;
+        }
+    }
+
+    private final class MyHandler extends HandlerCaller {
+        public static final int MSG_DESTROY = 1;
+        public static final int MSG_BINDER_DIED = 2;
+        public static final int MSG_UNBIND = 3;
+        public static final int MSG_ON_PENDING_REQUEST = 4;
+
+        public MyHandler(Context context) {
+            // Cannot use lambda - doesn't compile
+            super(context, FgThread.getHandler().getLooper(), new Callback() {
+                @Override
+                public void executeMessage(Message message) {
+                    if (mDestroyed) {
+                        Slog.w(LOG_TAG, "Not handling " + message + " as service for "
+                                + mComponentName + " is already destroyed");
+                        return;
+                    }
+                    switch (message.what) {
+                        case MSG_DESTROY: {
+                            handleDestroy();
+                        } break;
+
+                        case MSG_BINDER_DIED: {
+                            handleBinderDied();
+                        } break;
+
+                        case MSG_UNBIND: {
+                            handleUnbind();
+                        } break;
+
+                        case MSG_ON_PENDING_REQUEST: {
+                            handlePendingRequest((PendingRequest) message.obj);
+                        } break;
+                    }
+                }
+            }, false);
+        }
+    }
+
+    private static abstract class PendingRequest implements Runnable {
+        void cancel() {
+
+        }
+
+        /**
+         * @return whether this request leads to a final state where no
+         * other requests can be made.
+         */
+        boolean isFinal() {
+            return false;
+        }
+    }
+
+    private static final class PendingFillRequest extends PendingRequest {
+        private final Object mLock = new Object();
+        private final WeakReference<RemoteFillService> mWeakService;
+        private AssistStructure mStructure;
+        private Bundle mExtras;
+        private final IFillCallback mCallback;
+        private ICancellationSignal mCancellation;
+        private boolean mCancelled;
+
+        public PendingFillRequest(AssistStructure structure,
+                Bundle extras, RemoteFillService service) {
+            mStructure = structure;
+            mExtras = extras;
+            mWeakService = new WeakReference<>(service);
+            mCallback = new IFillCallback.Stub() {
+                @Override
+                public void onCancellable(ICancellationSignal cancellation) {
+                    synchronized (mLock) {
+                        final boolean cancelled;
+                        synchronized (mLock) {
+                            mCancellation = cancellation;
+                            cancelled = mCancelled;
+                        }
+                        if (cancelled) {
+                            try {
+                                cancellation.cancel();
+                            } catch (RemoteException e) {
+                                Slog.e(LOG_TAG, "Error requesting a cancellation", e);
+                            }
+                        }
+                    }
+                }
+
+                @Override
+                public void onSuccess(FillResponse response) {
+                    RemoteFillService remoteService = mWeakService.get();
+                    if (remoteService != null) {
+                        remoteService.dispatchOnFillRequestSuccess(
+                                PendingFillRequest.this, response);
+                    }
+                }
+
+                @Override
+                public void onFailure(CharSequence message) {
+                    RemoteFillService remoteService = mWeakService.get();
+                    if (remoteService != null) {
+                        remoteService.dispatchOnFillRequestFailure(
+                                PendingFillRequest.this, message);
+                    }
+                }
+            };
+        }
+
+        @Override
+        public void run() {
+            RemoteFillService remoteService = mWeakService.get();
+            if (remoteService != null) {
+                try {
+                    remoteService.mAutoFillService.onFillRequest(mStructure,
+                            mExtras, mCallback);
+                    synchronized (mLock) {
+                        mStructure = null;
+                        mExtras = null;
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Error calling on fill request", e);
+                    cancel();
+                }
+            }
+        }
+
+        @Override
+        public void cancel() {
+            final ICancellationSignal cancellation;
+            synchronized (mLock) {
+                if (mCancelled) {
+                    return;
+                }
+                mCancelled = true;
+                cancellation = mCancellation;
+            }
+            if (cancellation == null) {
+                return;
+            }
+            try {
+                cancellation.cancel();
+            } catch (RemoteException e) {
+                Slog.e(LOG_TAG, "Error cancelling a fill request", e);
+            }
+        }
+    }
+
+    private static final class PendingSaveRequest extends PendingRequest {
+        private final Object mLock = new Object();
+        private final WeakReference<RemoteFillService> mWeakService;
+        private AssistStructure mStructure;
+        private Bundle mExtras;
+        private final ISaveCallback mCallback;
+
+        public PendingSaveRequest(@NonNull AssistStructure structure,
+                @Nullable Bundle extras, @NonNull RemoteFillService service) {
+            mStructure = structure;
+            mExtras = extras;
+            mWeakService = new WeakReference<>(service);
+            mCallback = new ISaveCallback.Stub() {
+                @Override
+                public void onSuccess() {
+                    RemoteFillService service = mWeakService.get();
+                    if (service != null) {
+                        service.dispatchOnSaveRequestSuccess(
+                                PendingSaveRequest.this);
+                    }
+                }
+
+                @Override
+                public void onFailure(CharSequence message) {
+                    RemoteFillService service = mWeakService.get();
+                    if (service != null) {
+                        service.dispatchOnSaveRequestFailure(
+                                PendingSaveRequest.this, message);
+                    }
+                }
+            };
+        }
+
+        @Override
+        public void run() {
+            RemoteFillService service = mWeakService.get();
+            if (service != null) {
+                try {
+                    service.mAutoFillService.onSaveRequest(mStructure,
+                            mExtras, mCallback);
+                    synchronized (mLock) {
+                        mStructure = null;
+                        mExtras = null;
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Error calling on save request", e);
+                }
+            }
+        }
+
+        @Override
+        public boolean isFinal() {
+            return true;
+        }
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 88c05b5..2eab813 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1515,10 +1515,14 @@
                 // This isn't the current journal, so it must be a leftover.  Read
                 // out the package names mentioned there and schedule them for
                 // backup.
-                RandomAccessFile in = null;
+                DataInputStream in = null;
                 try {
                     Slog.i(TAG, "Found stale backup journal, scheduling");
-                    in = new RandomAccessFile(f, "r");
+                    // Journals will tend to be on the order of a few kilobytes(around 4k), hence,
+                    // setting the buffer size to 8192.
+                    InputStream bufferedInputStream = new BufferedInputStream(
+                            new FileInputStream(f), 8192);
+                    in = new DataInputStream(bufferedInputStream);
                     while (true) {
                         String packageName = in.readUTF();
                         if (MORE_DEBUG) Slog.i(TAG, "  " + packageName);
@@ -3371,7 +3375,7 @@
                 this.notifyAll();
             }
         }
-        
+
     }
 
     private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
@@ -3829,7 +3833,7 @@
         String mCurrentPassword;
         String mEncryptPassword;
 
-        PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, 
+        PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
                 boolean includeApks, boolean includeObbs, boolean includeShared,
                 boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
                 boolean doSystem, boolean doCompress, String[] packages, AtomicBoolean latch) {
@@ -4200,7 +4204,7 @@
         IBackupObserver mBackupObserver;
         boolean mUserInitiated;
 
-        PerformFullTransportBackupTask(IFullBackupRestoreObserver observer, 
+        PerformFullTransportBackupTask(IFullBackupRestoreObserver observer,
                 String[] whichPackages, boolean updateSchedule,
                 FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
                 boolean userInitiated) {
@@ -7947,20 +7951,20 @@
 
         /*
          * SKETCH OF OPERATION
-         * 
+         *
          * create one of these PerformUnifiedRestoreTask objects, telling it which
          * dataset & transport to address, and then parameters within the restore
          * operation: single target package vs many, etc.
          *
          * 1. transport.startRestore(token, list-of-packages).  If we need @pm@  it is
          * always placed first and the settings provider always placed last [for now].
-         * 
+         *
          * 1a [if we needed @pm@ then nextRestorePackage() and restore the PMBA inline]
-         * 
+         *
          *   [ state change => RUNNING_QUEUE ]
-         * 
+         *
          * NOW ITERATE:
-         * 
+         *
          * { 3. t.nextRestorePackage()
          *   4. does the metadata for this package allow us to restore it?
          *      does the on-disk app permit us to restore it? [re-check allowBackup etc]
@@ -7971,7 +7975,7 @@
          *       5c. call into agent to perform restore
          *       5d. tear down agent
          *       [ state change => RUNNING_QUEUE ]
-         * 
+         *
          *   6. else it's a stream dataset:
          *       [ state change => RESTORE_FULL ]
          *       6a. instantiate the engine for a stream restore: engine handles agent lifecycles
@@ -7979,12 +7983,12 @@
          *       6c. ITERATE getNextFullRestoreDataChunk() and copy data to engine runner socket
          *       [ state change => RUNNING_QUEUE ]
          * }
-         * 
+         *
          *   [ state change => FINAL ]
-         * 
+         *
          * 7. t.finishRestore(), release wakelock, etc.
-         * 
-         * 
+         *
+         *
          */
 
         // state INITIAL : set up for the restore and read the metadata if necessary
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 22eca77..ca708b6 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -181,6 +181,7 @@
     static final int MSG_SET_ACTIVE = 3020;
     static final int MSG_SET_INTERACTIVE = 3030;
     static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 3040;
+    static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
     static final int MSG_SWITCH_IME = 3050;
 
     static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
@@ -411,6 +412,11 @@
     boolean mInputShown;
 
     /**
+     * {@code true} if the current input method is in fullscreen mode.
+     */
+    boolean mInFullscreenMode;
+
+    /**
      * The Intent used to connect to the current input method.
      */
     Intent mCurIntent;
@@ -1265,8 +1271,8 @@
                 }
             }
 
-            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
-                    MSG_SET_ACTIVE, 0, mCurClient));
+            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
+                    MSG_SET_ACTIVE, 0, 0, mCurClient));
             executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
                     MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
             mCurClient.sessionRequested = false;
@@ -1297,7 +1303,8 @@
         return flags;
     }
 
-    InputBindResult attachNewInputLocked(boolean initial) {
+    InputBindResult attachNewInputLocked(
+            /* @InputMethodClient.StartInputReason */ final int startInputReason, boolean initial) {
         if (!mBoundToMethod) {
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
                     MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
@@ -1361,12 +1368,13 @@
         }
 
         return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
-                controlFlags);
+                controlFlags, startInputReason);
     }
 
     InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
             /* @InputConnectionInspector.missingMethods */ final int missingMethods,
-            @NonNull EditorInfo attribute, int controlFlags) {
+            @NonNull EditorInfo attribute, int controlFlags,
+            /* @InputMethodClient.StartInputReason */ final int startInputReason) {
         // If no method is currently selected, do nothing.
         if (mCurMethodId == null) {
             return mNoBinding;
@@ -1408,7 +1416,7 @@
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
-                return attachNewInputLocked(
+                return attachNewInputLocked(startInputReason,
                         (controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);
             }
             if (mHaveConnection) {
@@ -1549,7 +1557,8 @@
                     clearClientSessionLocked(mCurClient);
                     mCurClient.curSession = new SessionState(mCurClient,
                             method, session, channel);
-                    InputBindResult res = attachNewInputLocked(true);
+                    InputBindResult res = attachNewInputLocked(
+                            InputMethodClient.START_INPUT_REASON_SESSION_CREATED_BY_IME, true);
                     if (res.method != null) {
                         executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
                                 MSG_BIND_CLIENT, mCurClient.client, res));
@@ -1646,6 +1655,7 @@
         if (mStatusBar != null) {
             mStatusBar.setIconVisibility(mSlotIme, false);
         }
+        mInFullscreenMode = false;
     }
 
     @Override
@@ -2289,7 +2299,7 @@
                     }
                     if (attribute != null) {
                         return startInputUncheckedLocked(cs, inputContext, missingMethods,
-                                attribute, controlFlags);
+                                attribute, controlFlags, startInputReason);
                     }
                     return null;
                 }
@@ -2339,7 +2349,7 @@
                             if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
                             if (attribute != null) {
                                 res = startInputUncheckedLocked(cs, inputContext,
-                                        missingMethods, attribute, controlFlags);
+                                        missingMethods, attribute, controlFlags, startInputReason);
                                 didStart = true;
                             }
                             showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2365,7 +2375,7 @@
                             if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
                             if (attribute != null) {
                                 res = startInputUncheckedLocked(cs, inputContext,
-                                        missingMethods, attribute, controlFlags);
+                                        missingMethods, attribute, controlFlags, startInputReason);
                                 didStart = true;
                             }
                             showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2375,7 +2385,7 @@
                         if (DEBUG) Slog.v(TAG, "Window asks to always show input");
                         if (attribute != null) {
                             res = startInputUncheckedLocked(cs, inputContext, missingMethods,
-                                    attribute, controlFlags);
+                                    attribute, controlFlags, startInputReason);
                             didStart = true;
                         }
                         showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2384,7 +2394,7 @@
 
                 if (!didStart && attribute != null) {
                     res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
-                            controlFlags);
+                            controlFlags, startInputReason);
                 }
             }
         } finally {
@@ -2912,7 +2922,7 @@
             }
             case MSG_SET_ACTIVE:
                 try {
-                    ((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
+                    ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
                             + ((ClientState)msg.obj).pid + " uid "
@@ -2939,6 +2949,18 @@
                 }
                 return true;
             }
+            case MSG_REPORT_FULLSCREEN_MODE: {
+                final boolean fullscreen = msg.arg1 != 0;
+                final ClientState clientState = (ClientState)msg.obj;
+                try {
+                    clientState.client.reportFullscreenMode(fullscreen);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Got RemoteException sending "
+                            + "reportFullscreen(" + fullscreen + ") notification to pid="
+                            + clientState.pid + " uid=" + clientState.uid);
+                }
+                return true;
+            }
 
             // --------------------------------------------------------------
             case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
@@ -2959,8 +2981,9 @@
 
             // Inform the current client of the change in active status
             if (mCurClient != null && mCurClient.client != null) {
-                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
-                        MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mCurClient));
+                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
+                        MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
+                        mCurClient));
             }
         }
     }
@@ -3960,6 +3983,23 @@
     }
 
     @Override
+    public void reportFullscreenMode(IBinder token, boolean fullscreen) {
+        if (!calledFromValidUser()) {
+            return;
+        }
+        synchronized (mMethodMap) {
+            if (!calledWithValidToken(token)) {
+                return;
+            }
+            if (mCurClient != null && mCurClient.client != null) {
+                mInFullscreenMode = fullscreen;
+                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+                        MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
+            }
+        }
+    }
+
+    @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -4011,6 +4051,7 @@
                     + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
                     + " mShowForced=" + mShowForced
                     + " mInputShown=" + mInputShown);
+            p.println("  mInFullscreenMode=" + mInFullscreenMode);
             p.println("  mCurUserActionNotificationSequenceNumber="
                     + mCurUserActionNotificationSequenceNumber);
             p.println("  mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 4ab894f..42eb958 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.ActivityManager;
+import android.annotation.NonNull;
 import android.content.pm.PackageManagerInternal;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
@@ -62,6 +63,7 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
+import android.location.IBatchedLocationCallback;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssStatusListener;
 import android.location.IGnssStatusProvider;
@@ -101,6 +103,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -142,7 +145,7 @@
     private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
 
     // default background throttling interval if not overriden in settings
-    private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 10 * 60 * 1000;
+    private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
 
     // Location Providers may sometimes deliver location updates
     // slightly faster that requested - provide grace period so
@@ -229,6 +232,11 @@
 
     private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
 
+    private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
+    private IBatchedLocationCallback mGnssBatchingCallback;
+    private LinkedCallback mGnssBatchingDeathCallback;
+    private boolean mGnssBatchingInProgress = false;
+
     public LocationManagerService(Context context) {
         super();
         mContext = context;
@@ -545,6 +553,7 @@
             GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
                     mLocationHandler.getLooper());
             mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
+            mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
             mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
             mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
             addProviderLocked(gnssProvider);
@@ -1073,13 +1082,197 @@
      */
     @Override
     public int getGnssYearOfHardware() {
-        if (mGnssNavigationMessageProvider != null) {
+        if (mGnssSystemInfoProvider != null) {
             return mGnssSystemInfoProvider.getGnssYearOfHardware();
         } else {
             return 0;
         }
     }
 
+    /**
+     * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
+     * (try to) access GNSS information at this layer.
+     */
+    private boolean hasGnssPermissions(String packageName) {
+        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+        checkResolutionLevelIsSufficientForProviderUse(
+                allowedResolutionLevel,
+                LocationManager.GPS_PROVIDER);
+
+        int pid = Binder.getCallingPid();
+        int uid = Binder.getCallingUid();
+        long identity = Binder.clearCallingIdentity();
+        boolean hasLocationAccess;
+        try {
+            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        return hasLocationAccess;
+    }
+
+    /**
+     * Returns the GNSS batching size, if available.
+     */
+    @Override
+    public int getGnssBatchSize(String packageName) {
+        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
+            return mGnssBatchingProvider.getSize();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Adds a callback for GNSS Batching events, if permissions allow, which are transported
+     * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
+     */
+    @Override
+    public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
+        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
+            return false;
+        }
+
+        mGnssBatchingCallback = callback;
+        mGnssBatchingDeathCallback = new LinkedCallback(callback);
+        try {
+            callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
+        } catch (RemoteException e) {
+            // if the remote process registering the listener is already dead, just swallow the
+            // exception and return
+            Log.e(TAG, "Remote listener already died.", e);
+            return false;
+        }
+
+        return true;
+    }
+
+    private class LinkedCallback implements IBinder.DeathRecipient {
+        private final IBatchedLocationCallback mCallback;
+
+        public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
+            mCallback = callback;
+        }
+
+        @NonNull
+        public IBatchedLocationCallback getUnderlyingListener() {
+            return mCallback;
+        }
+
+        @Override
+        public void binderDied() {
+            Log.d(TAG, "Remote Batching Callback died: " + mCallback);
+            stopGnssBatch();
+            removeGnssBatchingCallback();
+        }
+    }
+
+    /**
+     * Removes callback for GNSS batching
+     */
+    @Override
+    public void removeGnssBatchingCallback() {
+        try {
+            mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
+                    0 /* flags */);
+        } catch (NoSuchElementException e) {
+            // if the death callback isn't connected (it should be...), log error, swallow the
+            // exception and return
+            Log.e(TAG, "Couldn't unlink death callback.", e);
+        }
+        mGnssBatchingCallback = null;
+        mGnssBatchingDeathCallback = null;
+    }
+
+
+    /**
+     * Starts GNSS batching, if available.
+     */
+    @Override
+    public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
+        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
+            return false;
+        }
+
+        if (mGnssBatchingInProgress) {
+            // Current design does not expect multiple starts to be called repeatedly
+            Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
+            // Try to clean up anyway, and continue
+            stopGnssBatch();
+        }
+
+        mGnssBatchingInProgress = true;
+        return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
+    }
+
+    /**
+     * Flushes a GNSS batch in progress
+     */
+    @Override
+    public void flushGnssBatch(String packageName) {
+        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (!hasGnssPermissions(packageName)) {
+            Log.e(TAG, "flushGnssBatch called without GNSS permissions");
+            return;
+        }
+
+        if (!mGnssBatchingInProgress) {
+            Log.w(TAG, "flushGnssBatch called with no batch in progress");
+        }
+
+        if (mGnssBatchingProvider != null) {
+             mGnssBatchingProvider.flush();
+        }
+    }
+
+    /**
+     * Stops GNSS batching
+     */
+    @Override
+    public boolean stopGnssBatch() {
+        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (mGnssBatchingProvider != null) {
+            mGnssBatchingInProgress = false;
+            return mGnssBatchingProvider.stop();
+        } else  {
+            return false;
+        }
+    }
+
+    @Override
+    public void reportLocationBatch(List<Location> locations) {
+        checkCallerIsProvider();
+
+        // Currently used only for GNSS locations - update permissions check if changed
+        if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
+            if (mGnssBatchingCallback == null) {
+                Slog.e(TAG, "reportLocationBatch() called without active Callback");
+                return;
+            }
+            try {
+                mGnssBatchingCallback.onLocationBatch(locations);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
+            }
+        } else {
+            Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
+        }
+    }
+
     private void addProviderLocked(LocationProviderInterface provider) {
         mProviders.add(provider);
         mProvidersByName.put(provider.getName(), provider);
@@ -2000,22 +2193,7 @@
 
     @Override
     public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
-                LocationManager.GPS_PROVIDER);
-
-        final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
-                return false;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-        if (mGnssStatusProvider == null) {
+        if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
             return false;
         }
 
@@ -2043,22 +2221,7 @@
     public boolean addGnssMeasurementsListener(
             IGnssMeasurementsListener listener,
             String packageName) {
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkResolutionLevelIsSufficientForProviderUse(
-                allowedResolutionLevel,
-                LocationManager.GPS_PROVIDER);
-
-        int pid = Binder.getCallingPid();
-        int uid = Binder.getCallingUid();
-        long identity = Binder.clearCallingIdentity();
-        boolean hasLocationAccess;
-        try {
-            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-
-        if (!hasLocationAccess || mGnssMeasurementsProvider == null) {
+        if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
             return false;
         }
         return mGnssMeasurementsProvider.addListener(listener);
@@ -2075,22 +2238,7 @@
     public boolean addGnssNavigationMessageListener(
             IGnssNavigationMessageListener listener,
             String packageName) {
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkResolutionLevelIsSufficientForProviderUse(
-                allowedResolutionLevel,
-                LocationManager.GPS_PROVIDER);
-
-        int pid = Binder.getCallingPid();
-        int uid = Binder.getCallingUid();
-        long identity = Binder.clearCallingIdentity();
-        boolean hasLocationAccess;
-        try {
-            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-
-        if (!hasLocationAccess || mGnssNavigationMessageProvider == null) {
+        if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
             return false;
         }
         return mGnssNavigationMessageProvider.addListener(listener);
@@ -2866,6 +3014,9 @@
                 pw.println(":");
                 provider.dump(fd, pw, args);
             }
+            if (mGnssBatchingInProgress) {
+                pw.println("  GNSS batching in progress");
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 8ef34dc..a073d8e 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -68,6 +68,7 @@
 import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
 
@@ -94,8 +95,10 @@
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -231,7 +234,7 @@
         }
         // Do not tie it to parent when parent does not have a screen lock
         final int parentId = mUserManager.getProfileParent(managedUserId).id;
-        if (!mStorage.hasPassword(parentId) && !mStorage.hasPattern(parentId)) {
+        if (!isUserSecure(parentId)) {
             if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
             return;
         }
@@ -378,7 +381,7 @@
         }
 
         final UserHandle userHandle = user.getUserHandle();
-        final boolean isSecure = mStorage.hasPassword(userId) || mStorage.hasPattern(userId);
+        final boolean isSecure = isUserSecure(userId);
         if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
             UserInfo parent = mUserManager.getProfileParent(userId);
             if (parent != null &&
@@ -453,35 +456,34 @@
     }
 
     public void onUnlockUser(final int userId) {
-        // Hide notification first, as tie managed profile lock takes time
-        hideEncryptionNotification(new UserHandle(userId));
+        // Perform tasks which require locks in LSS on a handler, as we are callbacks from
+        // ActivityManager.unlockUser()
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                // Hide notification first, as tie managed profile lock takes time
+                hideEncryptionNotification(new UserHandle(userId));
 
-        if (mUserManager.getUserInfo(userId).isManagedProfile()) {
-            // As tieManagedProfileLockIfNecessary() may try to unlock user, we should not do it
-            // in onUnlockUser() synchronously, otherwise it may cause a deadlock
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
+                // Now we have unlocked the parent user we should show notifications
+                // about any profiles that exist.
+                List<UserInfo> profiles = mUserManager.getProfiles(userId);
+                for (int i = 0; i < profiles.size(); i++) {
+                    UserInfo profile = profiles.get(i);
+                    final boolean isSecure = isUserSecure(profile.id);
+                    if (isSecure && profile.isManagedProfile()) {
+                        UserHandle userHandle = profile.getUserHandle();
+                        if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
+                                !mUserManager.isQuietModeEnabled(userHandle)) {
+                            showEncryptionNotificationForProfile(userHandle);
+                        }
+                    }
+                }
+
+                if (mUserManager.getUserInfo(userId).isManagedProfile()) {
                     tieManagedProfileLockIfNecessary(userId, null);
                 }
-            });
-        }
-
-        // Now we have unlocked the parent user we should show notifications
-        // about any profiles that exist.
-        List<UserInfo> profiles = mUserManager.getProfiles(userId);
-        for (int i = 0; i < profiles.size(); i++) {
-            UserInfo profile = profiles.get(i);
-            final boolean isSecure =
-                    mStorage.hasPassword(profile.id) || mStorage.hasPattern(profile.id);
-            if (isSecure && profile.isManagedProfile()) {
-                UserHandle userHandle = profile.getUserHandle();
-                if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
-                        !mUserManager.isQuietModeEnabled(userHandle)) {
-                    showEncryptionNotificationForProfile(userHandle);
-                }
             }
-        }
+        });
     }
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -809,6 +811,10 @@
         return mStorage.hasPattern(userId);
     }
 
+    private boolean isUserSecure(int userId) {
+        return mStorage.hasCredential(userId);
+    }
+
     private void setKeystorePassword(String password, int userHandle) {
         final KeyStore ks = KeyStore.getInstance();
         ks.onUserPasswordChanged(userHandle, password);
@@ -914,21 +920,52 @@
         }
     }
 
-    private byte[] getCurrentHandle(int userId) {
-        CredentialHash credential = mStorage.readCredentialHash(userId);
-
-        // sanity check
-        if (credential.type != LockPatternUtils.CREDENTIAL_TYPE_NONE && credential.hash == null) {
-            Slog.e(TAG, "Stored handle type [" + credential.type + "] but no handle available");
+    private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
+        if (mUserManager.getUserInfo(userId).isManagedProfile()) {
+            return null;
         }
-        return credential.hash;
+        Map<Integer, String> result = new ArrayMap<Integer, String>();
+        final List<UserInfo> profiles = mUserManager.getProfiles(userId);
+        final int size = profiles.size();
+        for (int i = 0; i < size; i++) {
+            final UserInfo profile = profiles.get(i);
+            if (!profile.isManagedProfile()) {
+                continue;
+            }
+            final int managedUserId = profile.id;
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
+                continue;
+            }
+            try {
+                result.put(userId, getDecryptedPasswordForTiedProfile(userId));
+            } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
+                    | NoSuchPaddingException | InvalidKeyException
+                    | InvalidAlgorithmParameterException | IllegalBlockSizeException
+                    | BadPaddingException | CertificateException | IOException e) {
+                // ignore
+            }
+        }
+        return result;
     }
 
-    private void onUserLockChanged(int userId) throws RemoteException {
+    /**
+     * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
+     * depending on the parent user's secure state.
+     *
+     * When clearing tied work challenges, a pre-computed password table for profiles are required,
+     * since changing password for profiles requires existing password, and existing passwords can
+     * only be computed before the parent user's password is cleared.
+     *
+     * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
+     * method again on profiles. However the recursion is guaranteed to terminate as this method
+     * terminates when the user is a managed profile.
+     */
+    private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
+            Map<Integer, String> profilePasswordMap) throws RemoteException {
         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
             return;
         }
-        final boolean isSecure = mStorage.hasPassword(userId) || mStorage.hasPattern(userId);
+        final boolean isSecure = isUserSecure(userId);
         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
         final int size = profiles.size();
         for (int i = 0; i < size; i++) {
@@ -941,11 +978,17 @@
                 if (isSecure) {
                     tieManagedProfileLockIfNecessary(managedUserId, null);
                 } else {
-                    clearUserKeyProtection(managedUserId);
-                    getGateKeeperService().clearSecureUserId(managedUserId);
-                    mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), managedUserId);
-                    setKeystorePassword(null, managedUserId);
-                    fixateNewestUserKeyAuth(managedUserId);
+                    // We use cached work profile password computed before clearing the parent's
+                    // credential, otherwise they get lost
+                    if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
+                        setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
+                                profilePasswordMap.get(managedUserId), managedUserId);
+                    } else {
+                        Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
+                        // Supplying null here would lead to untrusted credential change
+                        setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
+                                managedUserId);
+                    }
                     mStorage.removeChildProfileLock(managedUserId);
                     removeKeystoreProfileKey(managedUserId);
                 }
@@ -978,7 +1021,6 @@
 
     private void setLockCredentialInternal(String credential, int credentialType,
             String savedCredential, int userId) throws RemoteException {
-        byte[] currentHandle = getCurrentHandle(userId);
         if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
             if (credential != null) {
                 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
@@ -988,27 +1030,31 @@
             mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
             setKeystorePassword(null, userId);
             fixateNewestUserKeyAuth(userId);
-            onUserLockChanged(userId);
+            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
             notifyActivePasswordMetricsAvailable(null, userId);
             return;
         }
         if (credential == null) {
             throw new RemoteException("Null credential with mismatched credential type");
         }
+
+        CredentialHash currentHandle = mStorage.readCredentialHash(userId);
         if (isManagedProfileWithUnifiedLock(userId)) {
             // get credential from keystore when managed profile has unified lock
-            try {
-                savedCredential = getDecryptedPasswordForTiedProfile(userId);
-            } catch (FileNotFoundException e) {
-                Slog.i(TAG, "Child profile key not found");
-            } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
-                    | NoSuchAlgorithmException | NoSuchPaddingException
-                    | InvalidAlgorithmParameterException | IllegalBlockSizeException
-                    | BadPaddingException | CertificateException | IOException e) {
-                Slog.e(TAG, "Failed to decrypt child profile key", e);
+            if (savedCredential == null) {
+                try {
+                    savedCredential = getDecryptedPasswordForTiedProfile(userId);
+                } catch (FileNotFoundException e) {
+                    Slog.i(TAG, "Child profile key not found");
+                } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
+                        | NoSuchAlgorithmException | NoSuchPaddingException
+                        | InvalidAlgorithmParameterException | IllegalBlockSizeException
+                        | BadPaddingException | CertificateException | IOException e) {
+                    Slog.e(TAG, "Failed to decrypt child profile key", e);
+                }
             }
         } else {
-            if (currentHandle == null) {
+            if (currentHandle.hash == null) {
                 if (savedCredential != null) {
                     Slog.w(TAG, "Saved credential provided, but none stored");
                 }
@@ -1016,17 +1062,19 @@
             }
         }
 
-        byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, credential,
+        byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
                 userId);
         if (enrolledHandle != null) {
             CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
             mStorage.writeCredentialHash(willStore, userId);
-            // Refresh the auth token
-            setUserKeyProtection(userId, credential,
-                    doVerifyCredential(credential, credentialType, true, 0, userId,
-                            null /* progressCallback */));
+            // push new secret and auth token to vold
+            GateKeeperResponse gkResponse = getGateKeeperService()
+                    .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
+            setUserKeyProtection(userId, credential, convertResponse(gkResponse));
             fixateNewestUserKeyAuth(userId);
-            onUserLockChanged(userId);
+            // Refresh the auth token
+            doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
+            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
         } else {
             throw new RemoteException("Failed to enroll " +
                     (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
@@ -1034,6 +1082,26 @@
         }
     }
 
+    private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
+        VerifyCredentialResponse response;
+        int responseCode = gateKeeperResponse.getResponseCode();
+        if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
+            response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
+        } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
+            byte[] token = gateKeeperResponse.getPayload();
+            if (token == null) {
+                // something's wrong if there's no payload with a challenge
+                Slog.e(TAG, "verifyChallenge response had no associated payload");
+                response = VerifyCredentialResponse.ERROR;
+            } else {
+                response = new VerifyCredentialResponse(token);
+            }
+        } else {
+            response = VerifyCredentialResponse.ERROR;
+        }
+        return response;
+    }
+
     @VisibleForTesting
     protected void tieProfileLockToParent(int userId, String password) {
         if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
@@ -1123,6 +1191,7 @@
 
     private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
             throws RemoteException {
+        if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
         if (vcr == null) {
             throw new RemoteException("Null response verifying a credential we just set");
         }
@@ -1138,6 +1207,7 @@
     }
 
     private void clearUserKeyProtection(int userId) throws RemoteException {
+        if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
         addUserKeyAuth(userId, null, null);
     }
 
@@ -1171,6 +1241,7 @@
 
     private void fixateNewestUserKeyAuth(int userId)
             throws RemoteException {
+        if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
         final IStorageManager storageManager = mInjector.getStorageManager();
         final long callingId = Binder.clearCallingIdentity();
         try {
@@ -1370,27 +1441,10 @@
                 return VerifyCredentialResponse.ERROR;
             }
         }
-
-        VerifyCredentialResponse response;
-        boolean shouldReEnroll = false;
         GateKeeperResponse gateKeeperResponse = getGateKeeperService()
                 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
-        int responseCode = gateKeeperResponse.getResponseCode();
-        if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
-            response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
-        } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
-            byte[] token = gateKeeperResponse.getPayload();
-            if (token == null) {
-                // something's wrong if there's no payload with a challenge
-                Slog.e(TAG, "verifyChallenge response had no associated payload");
-                response = VerifyCredentialResponse.ERROR;
-            } else {
-                shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
-                response = new VerifyCredentialResponse(token);
-            }
-        } else {
-            response = VerifyCredentialResponse.ERROR;
-        }
+        VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
+        boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
 
diff --git a/services/core/java/com/android/server/LockSettingsShellCommand.java b/services/core/java/com/android/server/LockSettingsShellCommand.java
index e131251..1ab5303 100644
--- a/services/core/java/com/android/server/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/LockSettingsShellCommand.java
@@ -116,7 +116,7 @@
     }
 
     private void runClear() throws RemoteException {
-        mLockPatternUtils.clearLock(mCurrentUserId);
+        mLockPatternUtils.clearLock(mOld, mCurrentUserId);
         getOutPrintWriter().println("Lock credential cleared");
     }
 
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index c858036..385b1cf 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -290,6 +290,10 @@
             hasFile(getLegacyLockPatternFilename(userId));
     }
 
+    public boolean hasCredential(int userId) {
+        return hasPassword(userId) || hasPattern(userId);
+    }
+
     private boolean hasFile(String name) {
         byte[] contents = readFile(name);
         return contents != null && contents.length > 0;
@@ -650,4 +654,5 @@
             }
         }
     }
+
 }
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
index 1314110..f5fe3db 100644
--- a/services/core/java/com/android/server/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -51,6 +51,7 @@
     private static final int MSG_REGISTER_TRACKER = 2;
     private static final int MSG_UNREGISTER_TRACKER = 3;
     private static final int MSG_REMOVE_USER = 4;
+    private static final int MSG_SCHEDULE_STRONG_AUTH_TIMEOUT = 5;
 
     private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
             "LockSettingsStrongAuth.timeoutForUser";
@@ -128,6 +129,23 @@
         }
     }
 
+    private void handleScheduleStrongAuthTimeout(int userId) {
+        final DevicePolicyManager dpm =
+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, userId);
+        // cancel current alarm listener for the user (if there was one)
+        StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
+        if (alarm != null) {
+            mAlarmManager.cancel(alarm);
+        } else {
+            alarm = new StrongAuthTimeoutAlarmListener(userId);
+            mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
+        }
+        // schedule a new alarm listener for the user
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
+                alarm, mHandler);
+    }
+
     private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
         for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
             try {
@@ -151,7 +169,8 @@
     }
 
     public void removeUser(int userId) {
-        mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
+        final int argNotUsed = 0;
+        mHandler.obtainMessage(MSG_REMOVE_USER, userId, argNotUsed).sendToTarget();
     }
 
     public void requireStrongAuth(int strongAuthReason, int userId) {
@@ -169,29 +188,8 @@
     }
 
     public void reportSuccessfulStrongAuthUnlock(int userId) {
-        scheduleStrongAuthTimeout(userId);
-    }
-
-    private void scheduleStrongAuthTimeout(int userId) {
-        final DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, userId);
-        // cancel current alarm listener for the user (if there was one)
-        StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
-        if (alarm != null) {
-            mAlarmManager.cancel(alarm);
-        } else {
-            alarm = new StrongAuthTimeoutAlarmListener(userId);
-            mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
-        }
-        // schedule a new alarm listener for the user
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
-                    alarm, mHandler);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
+        final int argNotUsed = 0;
+        mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
     }
 
     private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
@@ -224,6 +222,9 @@
                 case MSG_REMOVE_USER:
                     handleRemoveUser(msg.arg1);
                     break;
+                case MSG_SCHEDULE_STRONG_AUTH_TIMEOUT:
+                    handleScheduleStrongAuthTimeout(msg.arg1);
+                    break;
             }
         }
     };
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 25016f6..0ac51b9 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -53,6 +53,7 @@
 import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -183,11 +184,12 @@
                 // connection.
                 if (DBG) Log.d(TAG, "No active scorers available.");
                 unbindFromScoringServiceIfNeeded();
-            } else if (activeScorer.packageName.equals(scorerPackageName)) {
+            } else if (activeScorer.getRecommendationServicePackageName().equals(scorerPackageName))
+            {
                 // The active scoring service changed in some way.
                 if (DBG) {
                     Log.d(TAG, "Possible change to the active scorer: "
-                            + activeScorer.packageName);
+                            + activeScorer.getRecommendationServicePackageName());
                 }
                 if (forceUnbind) {
                     unbindFromScoringServiceIfNeeded();
@@ -198,7 +200,8 @@
                 // bound to the correct scoring app. The logic in bindToScoringServiceIfNeeded()
                 // will sort that out to leave us bound to the most recent active scorer.
                 if (DBG) {
-                    Log.d(TAG, "Binding to " + activeScorer.packageName + " if needed.");
+                    Log.d(TAG, "Binding to " + activeScorer.getRecommendationServiceComponent()
+                            + " if needed.");
                 }
                 bindToScoringServiceIfNeeded(activeScorer);
             }
@@ -334,22 +337,19 @@
         bindToScoringServiceIfNeeded(scorerData);
     }
 
-    private void bindToScoringServiceIfNeeded(NetworkScorerAppData scorerData) {
-        if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + scorerData + ")");
-        if (scorerData != null && scorerData.recommendationServiceClassName != null) {
-            ComponentName componentName = new ComponentName(scorerData.packageName,
-                    scorerData.recommendationServiceClassName);
+    private void bindToScoringServiceIfNeeded(NetworkScorerAppData appData) {
+        if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + appData + ")");
+        if (appData != null) {
             synchronized (mServiceConnectionLock) {
                 // If we're connected to a different component then drop it.
                 if (mServiceConnection != null
-                        && !mServiceConnection.mComponentName.equals(componentName)) {
+                        && !mServiceConnection.mAppData.equals(appData)) {
                     unbindFromScoringServiceIfNeeded();
                 }
 
                 // If we're not connected at all then create a new connection.
                 if (mServiceConnection == null) {
-                    mServiceConnection = new ScoringServiceConnection(componentName,
-                            scorerData.packageUid);
+                    mServiceConnection = new ScoringServiceConnection(appData);
                 }
 
                 // Make sure the connection is connected (idempotent)
@@ -625,7 +625,7 @@
         }
     }
 
-    private boolean isCallerSystemUid() {
+    private boolean callerCanRequestScores() {
         // REQUEST_NETWORK_SCORES is a signature only permission.
         return mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES) ==
                  PackageManager.PERMISSION_GRANTED;
@@ -634,7 +634,7 @@
     @Override
     public boolean clearScores() {
         // Only the active scorer or the system should be allowed to flush all scores.
-        if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
+        if (isCallerActiveScorer(getCallingUid()) || callerCanRequestScores()) {
             final long token = Binder.clearCallingIdentity();
             try {
                 clearInternal();
@@ -672,10 +672,15 @@
     @Override
     public boolean isCallerActiveScorer(int callingUid) {
         synchronized (mServiceConnectionLock) {
-            return mServiceConnection != null && mServiceConnection.mScoringAppUid == callingUid;
+            return mServiceConnection != null
+                    && mServiceConnection.mAppData.packageUid == callingUid;
         }
     }
 
+    private boolean isCallerSystemProcess(int callingUid) {
+        return callingUid == Process.SYSTEM_UID;
+    }
+
     /**
      * Obtain the package name of the current active network scorer.
      *
@@ -686,16 +691,37 @@
     public String getActiveScorerPackage() {
         synchronized (mServiceConnectionLock) {
             if (mServiceConnection != null) {
-                return mServiceConnection.mComponentName.getPackageName();
+                return mServiceConnection.getPackageName();
             }
         }
         return null;
     }
 
+
+    /**
+     * Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
+     */
+    @Override
+    public NetworkScorerAppData getActiveScorer() {
+        // Only the system can access this data.
+        if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
+            synchronized (mServiceConnectionLock) {
+                if (mServiceConnection != null) {
+                    return mServiceConnection.mAppData;
+                }
+            }
+        } else {
+            throw new SecurityException(
+                    "Caller is neither the system process nor a score requester.");
+        }
+
+        return null;
+    }
+
     @Override
     public void disableScoring() {
         // Only the active scorer or the system should be allowed to disable scoring.
-        if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
+        if (isCallerActiveScorer(getCallingUid()) || callerCanRequestScores()) {
             // no-op for now but we could write to the setting if needed.
         } else {
             throw new SecurityException(
@@ -881,7 +907,7 @@
                 writer.println("Scoring is disabled.");
                 return;
             }
-            writer.println("Current scorer: " + currentScorer.packageName);
+            writer.println("Current scorer: " + currentScorer);
 
             sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
                 @Override
@@ -927,7 +953,7 @@
                 try {
                     for (int i = 0; i < count; i++) {
                         consumer.accept(callbackList.getBroadcastItem(i),
-                                callbackList.getRegisteredCallbackCookie(i));
+                                callbackList.getBroadcastCookie(i));
                     }
                 } finally {
                     callbackList.finishBroadcast();
@@ -966,21 +992,19 @@
     }
 
     private static class ScoringServiceConnection implements ServiceConnection {
-        private final ComponentName mComponentName;
-        private final int mScoringAppUid;
+        private final NetworkScorerAppData mAppData;
         private volatile boolean mBound = false;
         private volatile boolean mConnected = false;
         private volatile INetworkRecommendationProvider mRecommendationProvider;
 
-        ScoringServiceConnection(ComponentName componentName, int scoringAppUid) {
-            mComponentName = componentName;
-            mScoringAppUid = scoringAppUid;
+        ScoringServiceConnection(NetworkScorerAppData appData) {
+            mAppData = appData;
         }
 
         void connect(Context context) {
             if (!mBound) {
                 Intent service = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
-                service.setComponent(mComponentName);
+                service.setComponent(mAppData.getRecommendationServiceComponent());
                 mBound = context.bindServiceAsUser(service, this,
                         Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                         UserHandle.SYSTEM);
@@ -1010,6 +1034,10 @@
             return mRecommendationProvider;
         }
 
+        String getPackageName() {
+            return mAppData.getRecommendationServiceComponent().getPackageName();
+        }
+
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DBG) Log.d(TAG, "ScoringServiceConnection: " + name.flattenToString());
@@ -1027,7 +1055,9 @@
         }
 
         public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-            writer.println("ScoringServiceConnection: " + mComponentName + ", bound: " + mBound
+            writer.println("ScoringServiceConnection: "
+                    + mAppData.getRecommendationServiceComponent()
+                    + ", bound: " + mBound
                     + ", connected: " + mConnected);
         }
     }
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 2b5166e..feda273 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -20,6 +20,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.inputmethod.InputMethodUtils;
 import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerServiceCallback;
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 import com.android.internal.textservice.ITextServicesManager;
@@ -68,7 +69,6 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 public class TextServicesManagerService extends ITextServicesManager.Stub {
     private static final String TAG = TextServicesManagerService.class.getSimpleName();
@@ -549,56 +549,26 @@
                 return;
             }
             final SpellCheckerInfo sci = mSpellCheckerMap.get(sciId);
+            SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId);
             final int uid = Binder.getCallingUid();
-            if (mSpellCheckerBindGroups.containsKey(sciId)) {
-                final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId);
-                if (bindGroup != null) {
-                    final InternalDeathRecipient recipient =
-                            mSpellCheckerBindGroups.get(sciId).addListener(
-                                    tsListener, locale, scListener, uid, bundle);
-                    if (recipient == null) {
-                        if (DBG) {
-                            Slog.w(TAG, "Didn't create a death recipient.");
-                        }
-                        return;
-                    }
-                    if (bindGroup.mSpellChecker == null & bindGroup.mConnected) {
-                        Slog.e(TAG, "The state of the spell checker bind group is illegal.");
-                        bindGroup.removeAll();
-                    } else if (bindGroup.mSpellChecker != null) {
-                        if (DBG) {
-                            Slog.w(TAG, "Existing bind found. Return a spell checker session now. "
-                                    + "Listeners count = " + bindGroup.mListeners.size());
-                        }
-                        try {
-                            final ISpellCheckerSession session =
-                                    bindGroup.mSpellChecker.getISpellCheckerSession(
-                                            recipient.mScLocale, recipient.mScListener, bundle);
-                            if (session != null) {
-                                tsListener.onServiceConnected(session);
-                                return;
-                            } else {
-                                if (DBG) {
-                                    Slog.w(TAG, "Existing bind already expired. ");
-                                }
-                                bindGroup.removeAll();
-                            }
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "Exception in getting spell checker session: " + e);
-                            bindGroup.removeAll();
-                        }
-                    }
+            if (bindGroup == null) {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    bindGroup = startSpellCheckerServiceInnerLocked(sci);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+                if (bindGroup == null) {
+                    // startSpellCheckerServiceInnerLocked failed.
+                    return;
                 }
             }
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                startSpellCheckerServiceInnerLocked(
-                        sci, locale, tsListener, scListener, uid, bundle);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+
+            // Start getISpellCheckerSession async IPC, or just queue the request until the spell
+            // checker service is bound.
+            bindGroup.getISpellCheckerSessionOrQueueLocked(
+                     new SessionRequest(uid, locale, tsListener, scListener, bundle));
         }
-        return;
     }
 
     @Override
@@ -611,9 +581,8 @@
         }
     }
 
-    private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale,
-            ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
-            int uid, Bundle bundle) {
+    @Nullable
+    private SpellCheckerBindGroup startSpellCheckerServiceInnerLocked(SpellCheckerInfo info) {
         if (DBG) {
             Slog.w(TAG, "Start spell checker session inner locked.");
         }
@@ -627,11 +596,11 @@
         if (!bindCurrentSpellCheckerService(serviceIntent, connection,
                 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) {
             Slog.e(TAG, "Failed to get a spell checker service.");
-            return;
+            return null;
         }
-        final SpellCheckerBindGroup group = new SpellCheckerBindGroup(
-                connection, tsListener, locale, scListener, uid, bundle);
+        final SpellCheckerBindGroup group = new SpellCheckerBindGroup(connection);
         mSpellCheckerBindGroups.put(sciId, group);
+        return group;
     }
 
     @Override
@@ -814,16 +783,32 @@
                 pw.println("    " + ent.getKey() + " " + grp + ":");
                 pw.println("      " + "mInternalConnection=" + grp.mInternalConnection);
                 pw.println("      " + "mSpellChecker=" + grp.mSpellChecker);
-                pw.println("      " + "mBound=" + grp.mBound + " mConnected=" + grp.mConnected);
+                pw.println("      " + "mUnbindCalled=" + grp.mUnbindCalled);
+                pw.println("      " + "mConnected=" + grp.mConnected);
+                final int numPendingSessionRequests = grp.mPendingSessionRequests.size();
+                for (int i = 0; i < numPendingSessionRequests; i++) {
+                    final SessionRequest req = grp.mPendingSessionRequests.get(i);
+                    pw.println("      " + "Pending Request #" + i + ":");
+                    pw.println("        " + "mTsListener=" + req.mTsListener);
+                    pw.println("        " + "mScListener=" + req.mScListener);
+                    pw.println("        " + "mScLocale=" + req.mLocale + " mUid=" + req.mUserId);
+                }
+                final int numOnGoingSessionRequests = grp.mOnGoingSessionRequests.size();
+                for (int i = 0; i < numOnGoingSessionRequests; i++) {
+                    final SessionRequest req = grp.mOnGoingSessionRequests.get(i);
+                    pw.println("      " + "On going Request #" + i + ":");
+                    ++i;
+                    pw.println("        " + "mTsListener=" + req.mTsListener);
+                    pw.println("        " + "mScListener=" + req.mScListener);
+                    pw.println(
+                            "        " + "mScLocale=" + req.mLocale + " mUid=" + req.mUserId);
+                }
                 final int N = grp.mListeners.size();
                 for (int i = 0; i < N; i++) {
                     final InternalDeathRecipient listener = grp.mListeners.get(i);
                     pw.println("      " + "Listener #" + i + ":");
-                    pw.println("        " + "mTsListener=" + listener.mTsListener);
                     pw.println("        " + "mScListener=" + listener.mScListener);
                     pw.println("        " + "mGroup=" + listener.mGroup);
-                    pw.println("        " + "mScLocale=" + listener.mScLocale
-                            + " mUid=" + listener.mUid);
                 }
             }
             pw.println("");
@@ -832,25 +817,44 @@
         }
     }
 
+    private static final class SessionRequest {
+        @UserIdInt
+        public final int mUserId;
+        @Nullable
+        public final String mLocale;
+        @NonNull
+        public final ITextServicesSessionListener mTsListener;
+        @NonNull
+        public final ISpellCheckerSessionListener mScListener;
+        @Nullable
+        public final Bundle mBundle;
+
+        SessionRequest(@UserIdInt final int userId, @Nullable String locale,
+                @NonNull ITextServicesSessionListener tsListener,
+                @NonNull ISpellCheckerSessionListener scListener, @Nullable Bundle bundle) {
+            mUserId = userId;
+            mLocale = locale;
+            mTsListener = tsListener;
+            mScListener = scListener;
+            mBundle = bundle;
+        }
+    }
+
     // SpellCheckerBindGroup contains active text service session listeners.
     // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
     // mSpellCheckerBindGroups
     private final class SpellCheckerBindGroup {
         private final String TAG = SpellCheckerBindGroup.class.getSimpleName();
         private final InternalServiceConnection mInternalConnection;
-        private final CopyOnWriteArrayList<InternalDeathRecipient> mListeners =
-                new CopyOnWriteArrayList<>();
-        public boolean mBound;
-        public ISpellCheckerService mSpellChecker;
-        public boolean mConnected;
+        private final ArrayList<InternalDeathRecipient> mListeners = new ArrayList<>();
+        private boolean mUnbindCalled;
+        private ISpellCheckerService mSpellChecker;
+        private boolean mConnected;
+        private final ArrayList<SessionRequest> mPendingSessionRequests = new ArrayList<>();
+        private final ArrayList<SessionRequest> mOnGoingSessionRequests = new ArrayList<>();
 
-        public SpellCheckerBindGroup(InternalServiceConnection connection,
-                ITextServicesSessionListener listener, String locale,
-                ISpellCheckerSessionListener scListener, int uid, Bundle bundle) {
+        public SpellCheckerBindGroup(InternalServiceConnection connection) {
             mInternalConnection = connection;
-            mBound = true;
-            mConnected = false;
-            addListener(listener, locale, scListener, uid, bundle);
         }
 
         public void onServiceConnected(ISpellCheckerService spellChecker) {
@@ -858,55 +862,15 @@
                 Slog.d(TAG, "onServiceConnected");
             }
 
-            for (InternalDeathRecipient listener : mListeners) {
-                try {
-                    final ISpellCheckerSession session = spellChecker.getISpellCheckerSession(
-                            listener.mScLocale, listener.mScListener, listener.mBundle);
-                    synchronized(mSpellCheckerMap) {
-                        if (mListeners.contains(listener)) {
-                            listener.mTsListener.onServiceConnected(session);
-                        }
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Exception in getting the spell checker session."
-                            + "Reconnect to the spellchecker. ", e);
-                    removeAll();
-                    return;
-                }
-            }
             synchronized(mSpellCheckerMap) {
                 mSpellChecker = spellChecker;
                 mConnected = true;
+                // Dispatch pending getISpellCheckerSession requests.
+                mPendingSessionRequests.forEach(this::getISpellCheckerSessionLocked);
+                mPendingSessionRequests.clear();
             }
         }
 
-        public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener,
-                String locale, ISpellCheckerSessionListener scListener, int uid, Bundle bundle) {
-            if (DBG) {
-                Slog.d(TAG, "addListener: " + locale);
-            }
-            InternalDeathRecipient recipient = null;
-            synchronized(mSpellCheckerMap) {
-                try {
-                    final int size = mListeners.size();
-                    for (int i = 0; i < size; ++i) {
-                        if (mListeners.get(i).hasSpellCheckerListener(scListener)) {
-                            // do not add the lister if the group already contains this.
-                            return null;
-                        }
-                    }
-                    recipient = new InternalDeathRecipient(
-                            this, tsListener, locale, scListener, uid, bundle);
-                    scListener.asBinder().linkToDeath(recipient, 0);
-                    mListeners.add(recipient);
-                } catch(RemoteException e) {
-                    // do nothing
-                }
-                cleanLocked();
-            }
-            return recipient;
-        }
-
         public void removeListener(ISpellCheckerSessionListener listener) {
             if (DBG) {
                 Slog.w(TAG, "remove listener: " + listener.hashCode());
@@ -941,20 +905,29 @@
             if (DBG) {
                 Slog.d(TAG, "cleanLocked");
             }
-            // If there are no more active listeners, clean up.  Only do this
-            // once.
-            if (mBound && mListeners.isEmpty()) {
-                mBound = false;
-                final String sciId = mInternalConnection.mSciId;
-                SpellCheckerBindGroup cur = mSpellCheckerBindGroups.get(sciId);
-                if (cur == this) {
-                    if (DBG) {
-                        Slog.d(TAG, "Remove bind group.");
-                    }
-                    mSpellCheckerBindGroups.remove(sciId);
-                }
-                mContext.unbindService(mInternalConnection);
+            if (mUnbindCalled) {
+                return;
             }
+            // If there are no more active listeners, clean up.  Only do this once.
+            if (!mListeners.isEmpty()) {
+                return;
+            }
+            if (!mPendingSessionRequests.isEmpty()) {
+                return;
+            }
+            if (!mOnGoingSessionRequests.isEmpty()) {
+                return;
+            }
+            final String sciId = mInternalConnection.mSciId;
+            final SpellCheckerBindGroup cur = mSpellCheckerBindGroups.get(sciId);
+            if (cur == this) {
+                if (DBG) {
+                    Slog.d(TAG, "Remove bind group.");
+                }
+                mSpellCheckerBindGroups.remove(sciId);
+            }
+            mContext.unbindService(mInternalConnection);
+            mUnbindCalled = true;
         }
 
         public void removeAll() {
@@ -966,6 +939,59 @@
                     idr.mScListener.asBinder().unlinkToDeath(idr, 0);
                 }
                 mListeners.clear();
+                mPendingSessionRequests.clear();
+                mOnGoingSessionRequests.clear();
+                cleanLocked();
+            }
+        }
+
+        public void getISpellCheckerSessionOrQueueLocked(@NonNull SessionRequest request) {
+            if (mUnbindCalled) {
+                return;
+            }
+            if (!mConnected) {
+                mPendingSessionRequests.add(request);
+                return;
+            }
+            getISpellCheckerSessionLocked(request);
+        }
+
+        private void getISpellCheckerSessionLocked(@NonNull SessionRequest request) {
+            if (mUnbindCalled) {
+                return;
+            }
+            try {
+                mSpellChecker.getISpellCheckerSession(
+                        request.mLocale, request.mScListener, request.mBundle,
+                        new ISpellCheckerServiceCallbackBinder(this, request));
+                mOnGoingSessionRequests.add(request);
+            } catch(RemoteException e) {
+                // The target spell checker service is not available.  Better to reset the state.
+                removeAll();
+            }
+            cleanLocked();
+        }
+
+        void onSessionCreated(@Nullable final ISpellCheckerSession newSession,
+                @NonNull final SessionRequest request) {
+            synchronized (mSpellCheckerMap) {
+                if (mUnbindCalled) {
+                    return;
+                }
+                if (mOnGoingSessionRequests.remove(request)) {
+                    final InternalDeathRecipient recipient =
+                            new InternalDeathRecipient(this, request.mScListener);
+                    try {
+                        request.mTsListener.onServiceConnected(newSession);
+                        request.mScListener.asBinder().linkToDeath(recipient, 0);
+                        mListeners.add(recipient);
+                    } catch (RemoteException e) {
+                        // Technically this can happen if the spell checker client app is already
+                        // dead.  We can just forget about this request; the request is already
+                        // removed from mOnGoingSessionRequests and the death recipient listener is
+                        // not yet added to mListeners. There is nothing to release further.
+                    }
+                }
                 cleanLocked();
             }
         }
@@ -1008,21 +1034,13 @@
     }
 
     private static final class InternalDeathRecipient implements IBinder.DeathRecipient {
-        public final ITextServicesSessionListener mTsListener;
         public final ISpellCheckerSessionListener mScListener;
-        public final String mScLocale;
         private final SpellCheckerBindGroup mGroup;
-        public final int mUid;
-        public final Bundle mBundle;
+
         public InternalDeathRecipient(SpellCheckerBindGroup group,
-                ITextServicesSessionListener tsListener, String scLocale,
-                ISpellCheckerSessionListener scListener, int uid, Bundle bundle) {
-            mTsListener = tsListener;
+                ISpellCheckerSessionListener scListener) {
             mScListener = scListener;
-            mScLocale = scLocale;
             mGroup = group;
-            mUid = uid;
-            mBundle = bundle;
         }
 
         public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) {
@@ -1035,6 +1053,25 @@
         }
     }
 
+    private static final class ISpellCheckerServiceCallbackBinder
+            extends ISpellCheckerServiceCallback.Stub {
+        @NonNull
+        private final SpellCheckerBindGroup mBindGroup;
+        @NonNull
+        private final SessionRequest mRequest;
+
+        ISpellCheckerServiceCallbackBinder(@NonNull final SpellCheckerBindGroup bindGroup,
+                @NonNull final SessionRequest request) {
+            mBindGroup = bindGroup;
+            mRequest = request;
+        }
+
+        @Override
+        public void onSessionCreated(@Nullable ISpellCheckerSession newSession) {
+            mBindGroup.onSessionCreated(newSession, mRequest);
+        }
+    }
+
     private static final class TextServicesSettings {
         private final ContentResolver mResolver;
         @UserIdInt
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 6f2f2c4..acacb9e 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -772,7 +772,8 @@
     }
 
     private void registerVrStateListener() {
-        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
+        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
+                Context.VR_SERVICE));
         try {
             if (vrManager != null) {
                 vrManager.registerListener(mVrStateCallbacks);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index bfa3f04..fbc4440 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -287,16 +287,17 @@
                      * and then rebuild the cache. All under the cache lock. But that change is too
                      * large at this point.
                      */
+                    final String removedPackageName = intent.getData().toString();
                     Runnable purgingRunnable = new Runnable() {
                         @Override
                         public void run() {
                             purgeOldGrantsAll();
                             // Notify authenticator about removed app?
+                            removeVisibilityValuesForPackage(removedPackageName);
                         }
                     };
                     mHandler.post(purgingRunnable);
                 }
-
             }
         }, intentFilter);
 
@@ -429,7 +430,7 @@
 
     @Override
     public boolean addAccountExplicitlyWithVisibility(Account account, String password,
-            Bundle extras, Map uidToVisibility) {
+            Bundle extras, Map packageToVisibility) {
         Bundle.setDefusable(extras, true);
 
         final int callingUid = Binder.getCallingUid();
@@ -455,7 +456,7 @@
         try {
             UserAccounts accounts = getUserAccounts(userId);
             return addAccountInternal(accounts, account, password, extras, callingUid,
-                    (Map<Integer, Integer>) uidToVisibility);
+                    (Map<String, Integer>) packageToVisibility);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -505,7 +506,7 @@
                 if (accountsOfType != null) {
                     for (Account account : accountsOfType) {
                         result.put(account,
-                                resolveAccountVisibility(account, uid, packageName, accounts));
+                                resolveAccountVisibility(account, packageName, accounts));
                     }
                 }
             }
@@ -514,7 +515,7 @@
     }
 
     @Override
-    public Map<Integer, Integer> getUidsAndVisibilityForAccount(Account account) {
+    public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
         if (account == null) throw new IllegalArgumentException("account is null");
         int callingUid = Binder.getCallingUid();
         int userId = UserHandle.getUserId(callingUid);
@@ -525,18 +526,18 @@
                     String.format("uid %s cannot get secrets for account %s", callingUid, account);
             throw new SecurityException(msg);
         }
-        return getUidsAndVisibilityForAccount(account, accounts);
+        return getPackagesAndVisibilityForAccount(account, accounts);
     }
 
     /**
-     * Returns all UIDs and visibility values, which were set for given account
+     * Returns all package names and visibility values, which were set for given account.
      *
-     * @param account account
+     * @param account Account to get visibility values.
      * @param accounts UserAccount that currently hosts the account and application
      *
-     * @return Map from uid to visibility.
+     * @return Map from package names to visibility.
      */
-    private Map<Integer, Integer> getUidsAndVisibilityForAccount(Account account,
+    private Map<String, Integer> getPackagesAndVisibilityForAccount(Account account,
             UserAccounts accounts) {
         final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
         try {
@@ -548,7 +549,7 @@
     }
 
     @Override
-    public int getAccountVisibility(Account a, int uid) {
+    public int getAccountVisibility(Account a, String packageName) {
         if (a == null) throw new IllegalArgumentException("account is null");
         int callingUid = Binder.getCallingUid();
         if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
@@ -559,23 +560,24 @@
                     a.type);
             throw new SecurityException(msg);
         }
-        return getAccountVisibility(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
+        return getAccountVisibility(a, packageName,
+                getUserAccounts(UserHandle.getUserId(callingUid)));
     }
 
     /**
-     * Method gets visibility for given account and UID from the database
+     * Method returns visibility for given account and package name.
      *
-     * @param account The account to check visibility of
-     * @param uid UID to check visibility of
+     * @param account The account to check visibility.
+     * @param packageName Package name to check visibility.
      * @param accounts UserAccount that currently hosts the account and application
      *
      * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
      *
      */
-    private int getAccountVisibility(Account account, int uid, UserAccounts accounts) {
+    private int getAccountVisibility(Account account, String packageName, UserAccounts accounts) {
         final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
         try {
-            Integer visibility = accounts.accountsDb.findAccountVisibility(account, uid);
+            Integer visibility = accounts.accountsDb.findAccountVisibility(account, packageName);
             return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
@@ -586,19 +588,29 @@
      * Method which handles default values for Account visibility.
      *
      * @param account The account to check visibility.
-     * @param uid UID to check visibility.
-     * @param packageName Package name to check visibility - the method assumes that it has the same
-     *        uid as specified in the parameter.
+     * @param packageName Package name to check visibility
      * @param accounts UserAccount that currently hosts the account and application
      *
      * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
      *
      */
-    private Integer resolveAccountVisibility(Account account, int uid, String packageName,
+    private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
             UserAccounts accounts) {
-        if (packageName == null) {
-            packageName = getPackageNameForUid(uid);
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+
+        int uid = -1;
+        try {
+            long identityToken = clearCallingIdentity();
+            try {
+                uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
+            } finally {
+                restoreCallingIdentity(identityToken);
+            }
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, "Package not found " + e.getMessage());
+            return AccountManager.VISIBILITY_NOT_VISIBLE;
         }
+
         // System visibility can not be restricted.
         if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
             return AccountManager.VISIBILITY_VISIBLE;
@@ -612,20 +624,23 @@
             return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
         }
 
+        if (isSpecialPackageKey(packageName)) {
+            Log.d(TAG, "Package name is forbidden: " + packageName);
+            return AccountManager.VISIBILITY_NOT_VISIBLE;
+        }
+
         // Return stored value if it was set.
-        int visibility = getAccountVisibility(account, uid, accounts);
+        int visibility = getAccountVisibility(account, packageName, accounts);
 
         if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
             return visibility;
         }
 
-        if (isPermittedForPackage(packageName, accounts.userId,
-                Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
-            return AccountManager.VISIBILITY_VISIBLE;
+        boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId,
+                Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
 
-        }
-        // Profile owner gets visibility by default.
-        if(isProfileOwner(uid)) {
+        // Device/Profile owner gets visibility by default.
+        if (isProfileOwner(uid)) {
             return AccountManager.VISIBILITY_VISIBLE;
         }
         // Apps with READ_CONTACTS permission get visibility by default even post O.
@@ -634,17 +649,17 @@
         boolean preO = isPreOApplication(packageName);
         if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
                 || (preO && checkGetAccountsPermission(packageName, accounts.userId))
-                || canReadContacts) {
+                || canReadContacts || isPrivileged) {
             // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
             // match.
             visibility = getAccountVisibility(account,
-                    AccountManager.UID_KEY_DEFAULT_LEGACY_VISIBILITY, accounts);
+                    AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts);
             if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
                 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
             }
         } else {
-            visibility = getAccountVisibility(account, AccountManager.UID_KEY_DEFAULT_VISIBILITY,
-                    accounts);
+            visibility = getAccountVisibility(account,
+                    AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts);
             if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
                 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
             }
@@ -655,7 +670,7 @@
     /**
      * Checks targetSdk for a package;
      *
-     * @param packageName Package Name
+     * @param packageName Package name
      *
      * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
      *         undefined
@@ -682,7 +697,7 @@
     }
 
     @Override
-    public boolean setAccountVisibility(Account a, int uid, int newVisibility) {
+    public boolean setAccountVisibility(Account a, String packageName, int newVisibility) {
         if (a == null) throw new IllegalArgumentException("account is null");
         int callingUid = Binder.getCallingUid();
         if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
@@ -693,38 +708,42 @@
                     a.type);
             throw new SecurityException(msg);
         }
-        return setAccountVisibility(a, uid, newVisibility, true /* notify */,
+        return setAccountVisibility(a, packageName, newVisibility, true /* notify */,
                 getUserAccounts(UserHandle.getUserId(callingUid)));
     }
 
     /**
-     * Gives a certain UID, represented a application, access to an account. This method
-     * is called indirectly by the Authenticator.
+     * Updates visibility for given account name and package.
      *
-     * @param account Account to update visibility
-     * @param uid to add visibility of the Account
-     * @param newVisibility new visibility
+     * @param account Account to update visibility.
+     * @param packageName Package name for which visibility is updated.
+     * @param newVisibility New visibility calue
      * @param notify if the flag is set applications will get notification about visibility change
      * @param accounts UserAccount that currently hosts the account and application
      *
      * @return True if account visibility was changed.
      */
-    private boolean setAccountVisibility(Account account, int uid, int newVisibility,
+    private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
             boolean notify, UserAccounts accounts) {
         synchronized (accounts.cacheLock) {
             LinkedHashSet<String> interestedPackages;
             if (notify) {
-                if (uid < 0) {
+                if (isSpecialPackageKey(packageName)) {
                     interestedPackages = getRequestingPackageNames(account.type, accounts);
                 } else {
-                    interestedPackages = new LinkedHashSet<>();
-                    String[] subPackages = mPackageManager.getPackagesForUid(uid);
-                    if (subPackages != null) {
-                        Collections.addAll(interestedPackages, subPackages);
+                    if (!packageExistsForUser(packageName, accounts.userId)) {
+                        return false; // package is not installed.
                     }
+                    interestedPackages = new LinkedHashSet<>();
+                    interestedPackages.add(packageName);
                 }
             } else {
                 // Notifications will not be send.
+                if (!isSpecialPackageKey(packageName) &&
+                        !packageExistsForUser(packageName, accounts.userId)) {
+                    // package is not installed and not meta value.
+                    return false;
+                }
                 interestedPackages = new LinkedHashSet<>();
             }
             Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
@@ -734,14 +753,15 @@
                 return false;
             }
             int index = 0;
-            for (String packageName : interestedPackages) {
+            for (String interestedPackage : interestedPackages) {
                 interestedPackagesVisibility[index++] =
-                        resolveAccountVisibility(account, uid, packageName, accounts);
+                        resolveAccountVisibility(account, interestedPackage, accounts);
             }
 
             final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
             try {
-                if (!accounts.accountsDb.setAccountVisibility(accountId, uid, newVisibility)) {
+                if (!accounts.accountsDb.setAccountVisibility(accountId, packageName,
+                        newVisibility)) {
                     return false;
                 }
             } finally {
@@ -749,10 +769,10 @@
             }
 
             index = 0;
-            for (String packageName : interestedPackages) {
-                int visibility = resolveAccountVisibility(account, uid, packageName, accounts);
+            for (String interestedPackage : interestedPackages) {
+                int visibility = resolveAccountVisibility(account, interestedPackage, accounts);
                 if (visibility != interestedPackagesVisibility[index++]) {
-                        sendNotification(packageName, account, accounts.userId);
+                        sendNotification(interestedPackage, account, accounts.userId);
                 }
             }
             if (notify) {
@@ -777,23 +797,40 @@
         LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
                 accounts);
         for (String packageName : interestedPackages) {
-            try {
-                final int uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
-                int visibility = resolveAccountVisibility(account, uid, packageName, accounts);
-                if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
-                    sendNotification(packageName, account, accounts.userId);
-                }
-            } catch (NameNotFoundException e) {
-                // ignore
+            int visibility = resolveAccountVisibility(account, packageName, accounts);
+            if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
+                sendNotification(packageName, account, accounts.userId);
             }
         }
     }
 
-    LinkedHashSet<String> getRequestingPackageNames(String accountType, UserAccounts accouns) {
+    LinkedHashSet<String> getRequestingPackageNames(String accountType, UserAccounts accounts) {
         // TODO return packages registered to get notifications.
         return new LinkedHashSet<String>();
     }
 
+    private boolean packageExistsForUser(String packageName, int userId) {
+        try {
+            long identityToken = clearCallingIdentity();
+            try {
+                mPackageManager.getPackageUidAsUser(packageName, userId);
+                return true; // package exist
+            } finally {
+                restoreCallingIdentity(identityToken);
+            }
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if packageName is one of special values.
+     */
+    private boolean isSpecialPackageKey(String packageName) {
+        return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)
+                || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName));
+    }
+
     private void sendAccountsChangedBroadcast(int userId) {
         Log.i(TAG, "the accounts changed, sending broadcast of "
                 + ACCOUNTS_CHANGED_INTENT.getAction());
@@ -1075,6 +1112,20 @@
         }
     }
 
+    private void removeVisibilityValuesForPackage(String packageName) {
+        synchronized (mUsers) {
+          for (int i = 0; i < mUsers.size(); i++) {
+              UserAccounts accounts = mUsers.valueAt(i);
+              try {
+                  int uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
+              } catch (NameNotFoundException e) {
+                  // package does not exist - remove visibility values
+                  accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
+              }
+          }
+        }
+    }
+
     private void onUserRemoved(Intent intent) {
         int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
         if (userId < 1) return;
@@ -1472,7 +1523,7 @@
     }
 
     private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
-            Bundle extras, int callingUid, Map<Integer, Integer> uidToVisibility) {
+            Bundle extras, int callingUid, Map<String, Integer> packageToVisibility) {
         Bundle.setDefusable(extras, true);
         if (account == null) {
             return false;
@@ -1513,9 +1564,9 @@
                     }
                 }
 
-                if (uidToVisibility != null) {
-                    for (Entry<Integer, Integer> entry : uidToVisibility.entrySet()) {
-                        setAccountVisibility(account, entry.getKey() /* uid */,
+                if (packageToVisibility != null) {
+                    for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
+                        setAccountVisibility(account, entry.getKey() /* package */,
                                 entry.getValue() /* visibility */, false /* notify */, accounts);
                     }
                 }
@@ -1569,6 +1620,7 @@
     public void hasFeatures(IAccountManagerResponse response,
             Account account, String[] features, String opPackageName) {
         int callingUid = Binder.getCallingUid();
+        mAppOpsManager.checkPackage(callingUid, opPackageName);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "hasFeatures: " + account
                     + ", response " + response
@@ -1982,14 +2034,7 @@
             int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
             int index = 0;
             for (String packageName : interestedPackages) {
-                int visibility = AccountManager.VISIBILITY_NOT_VISIBLE;
-                try {
-                    final int uid = mPackageManager.getPackageUidAsUser(packageName,
-                            UserHandle.getUserId(callingUid));
-                    visibility = resolveAccountVisibility(account, uid, packageName, accounts);
-                } catch (NameNotFoundException e) {
-                    // ignore
-                }
+                int visibility = resolveAccountVisibility(account, packageName, accounts);
                 visibilityForInterestedPackages[index++] = visibility;
             }
             accounts.accountsDb.beginTransaction();
@@ -3663,7 +3708,7 @@
         // In addition to the permissions required to get an auth token we also allow
         // the account to be accessed by apps for which user or authenticator granted visibility.
 
-        int visibility = resolveAccountVisibility(account, uid, packageName,
+        int visibility = resolveAccountVisibility(account, packageName,
                 getUserAccounts(UserHandle.getUserId(uid)));
         return (visibility == AccountManager.VISIBILITY_VISIBLE
                 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
@@ -3870,6 +3915,7 @@
     @NonNull
     public Account[] getAccounts(int userId, String opPackageName) {
         int callingUid = Binder.getCallingUid();
+        mAppOpsManager.checkPackage(callingUid, opPackageName);
         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
                 opPackageName);
         if (visibleAccountTypes.isEmpty()) {
@@ -3890,7 +3936,7 @@
     }
 
     /**
-     * Returns accounts for all running users.
+     * Returns accounts for all running users, ignores visibility values.
      *
      * @hide
      */
@@ -3906,7 +3952,11 @@
         return getAccounts(runningUserIds);
     }
 
-    /** {@hide} */
+    /**
+     * Returns accounts for all users, ignores visibility values.
+     *
+     * @hide
+     */
     @NonNull
     public AccountAndUser[] getAllAccounts() {
         final List<UserInfo> users = getUserManager().getUsers(true);
@@ -3924,10 +3974,12 @@
             UserAccounts userAccounts = getUserAccounts(userId);
             if (userAccounts == null) continue;
             synchronized (userAccounts.cacheLock) {
-                Account[] accounts = getAccountsFromCacheLocked(userAccounts, null,
+                Account[] accounts = getAccountsFromCacheLocked(
+                        userAccounts,
+                        null /* type */,
                         Binder.getCallingUid(),
-                        null,
-                        false /* incl managed not visible*/);
+                        null /* packageName */,
+                        false /* include managed not visible*/);
                 for (int a = 0; a < accounts.length; a++) {
                     runningAccounts.add(new AccountAndUser(accounts[a], userId));
                 }
@@ -3941,9 +3993,10 @@
     @Override
     @NonNull
     public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
-        // Need calling package
-        return getAccountsAsUser(type, userId, null /* callingPackage */, -1, opPackageName,
-               false /* includeUserManagedNotVisible */);
+        int callingUid = Binder.getCallingUid();
+        mAppOpsManager.checkPackage(callingUid, opPackageName);
+        return getAccountsAsUser(type, userId, opPackageName /* callingPackage */, -1,
+                opPackageName, false /* includeUserManagedNotVisible */);
     }
 
     @NonNull
@@ -4112,6 +4165,7 @@
     public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
         int callingUid = Binder.getCallingUid();
         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
+            // Don't do opPackageName check - caller is system.
             throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
                     + callingUid + " with uid=" + uid);
         }
@@ -4125,6 +4179,7 @@
             String opPackageName) {
         int callingUid =  Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
+        mAppOpsManager.checkPackage(callingUid, opPackageName);
         int packageUid = -1;
         try {
             packageUid = mPackageManager.getPackageUidAsUser(packageName, userId);
@@ -4148,6 +4203,7 @@
             String[] features,
             String opPackageName) {
         int callingUid = Binder.getCallingUid();
+        mAppOpsManager.checkPackage(callingUid, opPackageName);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAccounts: accountType " + type
                     + ", response " + response
@@ -4738,7 +4794,7 @@
                 userAccounts.accountsDb.dumpDeAccountsTable(fout);
             } else {
                 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
-                        Process.SYSTEM_UID, null, false);
+                        Process.SYSTEM_UID, null /* packageName */, false);
                 fout.println("Accounts: " + accounts.length);
                 for (Account account : accounts) {
                     fout.println("  " + account);
@@ -4954,7 +5010,7 @@
 
     // Method checks visibility for applications targeing API level below {@link
     // android.os.Build.VERSION_CODES#O},
-    // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVELEGED permission.
+    // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission.
     private boolean checkGetAccountsPermission(String packageName, int userId) {
         return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS,
                 Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
@@ -5307,8 +5363,7 @@
         // filter based on visibility.
         Map<Account, Integer> firstPass = new HashMap<>();
         for (Account account : unfiltered) {
-            int visibility =
-                    resolveAccountVisibility(account, callingUid, callingPackage, accounts);
+            int visibility = resolveAccountVisibility(account, callingPackage, accounts);
             if ((visibility == AccountManager.VISIBILITY_VISIBLE
                     || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
                     || (includeManagedNotVisible
@@ -5403,6 +5458,9 @@
      */
     protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
             int callingUid, String callingPackage, boolean includeManagedNotVisible) {
+        if (callingPackage == null) {
+            callingPackage = getPackageNameForUid(callingUid);
+        }
         if (accountType != null) {
             final Account[] accounts = userAccounts.accountCache.get(accountType);
             if (accounts == null) {
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
index 85e4b5f..22543cb 100644
--- a/services/core/java/com/android/server/accounts/AccountsDb.java
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -54,7 +54,7 @@
     private static final String DATABASE_NAME = "accounts.db";
     private static final int PRE_N_DATABASE_VERSION = 9;
     private static final int CE_DATABASE_VERSION = 10;
-    private static final int DE_DATABASE_VERSION = 2; // Added visibility support in O.
+    private static final int DE_DATABASE_VERSION = 3; // Added visibility support in O
 
 
     static final String TABLE_ACCOUNTS = "accounts";
@@ -75,7 +75,7 @@
 
     private static final String TABLE_VISIBILITY = "visibility";
     private static final String VISIBILITY_ACCOUNTS_ID = "accounts_id";
-    private static final String VISIBILITY_UID = "_uid";
+    private static final String VISIBILITY_PACKAGE = "_package";
     private static final String VISIBILITY_VALUE = "value";
 
     private static final String TABLE_GRANTS = "grants";
@@ -252,7 +252,7 @@
                 createAccountsDeletionTrigger(db);
                 db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
                 db.execSQL("DROP TABLE IF EXISTS " + TABLE_DEBUG);
-                oldVersion ++;
+                oldVersion++;
             }
 
             if (oldVersion != newVersion) {
@@ -559,9 +559,9 @@
         private void createAccountsVisibilityTable(SQLiteDatabase db) {
             db.execSQL("CREATE TABLE " + TABLE_VISIBILITY + " ( "
                   + VISIBILITY_ACCOUNTS_ID + " INTEGER NOT NULL, "
-                  + VISIBILITY_UID + " TEXT NOT NULL, "
+                  + VISIBILITY_PACKAGE + " TEXT NOT NULL, "
                   + VISIBILITY_VALUE + " INTEGER, "
-                  + "PRIMARY KEY(" + VISIBILITY_ACCOUNTS_ID + "," + VISIBILITY_UID + "))");
+                  + "PRIMARY KEY(" + VISIBILITY_ACCOUNTS_ID + "," + VISIBILITY_PACKAGE + "))");
         }
 
         static void createDebugTable(SQLiteDatabase db) {
@@ -591,9 +591,18 @@
             Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
 
             if (oldVersion == 1) {
-              createAccountsVisibilityTable(db);
-              createAccountsDeletionVisibilityCleanupTrigger(db);
-              ++oldVersion;
+                createAccountsVisibilityTable(db);
+                createAccountsDeletionVisibilityCleanupTrigger(db);
+                oldVersion = 3; // skip version 2 which had uid based table
+            }
+
+            if (oldVersion == 2) {
+                // Remove uid based table and replace it with packageName based
+                db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "DeleteVisibility");
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_VISIBILITY);
+                createAccountsVisibilityTable(db);
+                createAccountsDeletionVisibilityCleanupTrigger(db);
+                oldVersion++;
             }
 
             if (oldVersion != newVersion) {
@@ -890,20 +899,20 @@
                 new String[] {Integer.toString(uid)}) > 0;
     }
 
-    boolean setAccountVisibility(long accountId, int uid, int visibility) {
+    boolean setAccountVisibility(long accountId, String packageName, int visibility) {
         SQLiteDatabase db = mDeDatabase.getWritableDatabase();
         ContentValues values = new ContentValues();
         values.put(VISIBILITY_ACCOUNTS_ID, String.valueOf(accountId));
-        values.put(VISIBILITY_UID, String.valueOf(uid));
+        values.put(VISIBILITY_PACKAGE, packageName);
         values.put(VISIBILITY_VALUE, String.valueOf(visibility));
         return (db.replace(TABLE_VISIBILITY, VISIBILITY_VALUE, values) != -1);
     }
 
-    Integer findAccountVisibility(Account account, int uid) {
+    Integer findAccountVisibility(Account account, String packageName) {
         SQLiteDatabase db = mDeDatabase.getWritableDatabase();
         final Cursor cursor = db.query(TABLE_VISIBILITY, new String[] {VISIBILITY_VALUE},
-                SELECTION_ACCOUNTS_ID_BY_ACCOUNT + " AND " + VISIBILITY_UID + "=? ",
-                new String[] {account.name, account.type, String.valueOf(uid)}, null, null, null);
+                SELECTION_ACCOUNTS_ID_BY_ACCOUNT + " AND " + VISIBILITY_PACKAGE + "=? ",
+                new String[] {account.name, account.type, packageName}, null, null, null);
         try {
             while (cursor.moveToNext()) {
                 return cursor.getInt(0);
@@ -914,11 +923,11 @@
         return null;
     }
 
-    Integer findAccountVisibility(long accountId, int uid) {
+    Integer findAccountVisibility(long accountId, String packageName) {
         SQLiteDatabase db = mDeDatabase.getWritableDatabase();
         final Cursor cursor = db.query(TABLE_VISIBILITY, new String[] {VISIBILITY_VALUE},
-                VISIBILITY_ACCOUNTS_ID + "=? AND " + VISIBILITY_UID + "=? ",
-                new String[] {String.valueOf(accountId), String.valueOf(uid)}, null, null, null);
+                VISIBILITY_ACCOUNTS_ID + "=? AND " + VISIBILITY_PACKAGE + "=? ",
+                new String[] {String.valueOf(accountId), packageName}, null, null, null);
         try {
             while (cursor.moveToNext()) {
                 return cursor.getInt(0);
@@ -944,18 +953,18 @@
     }
 
     /**
-     * Returns a map from uid to visibility value.
+     * Returns a map from packageNames to visibility.
      */
-    Map<Integer, Integer> findAllVisibilityValuesForAccount(Account account) {
+    Map<String, Integer> findAllVisibilityValuesForAccount(Account account) {
         SQLiteDatabase db = mDeDatabase.getReadableDatabase();
-        Map<Integer, Integer> result = new HashMap<>();
+        Map<String, Integer> result = new HashMap<>();
         final Cursor cursor =
-                db.query(TABLE_VISIBILITY, new String[] {VISIBILITY_UID, VISIBILITY_VALUE},
-                        SELECTION_ACCOUNTS_ID_BY_ACCOUNT,
-                        new String[] {account.name, account.type}, null, null, null);
+                db.query(TABLE_VISIBILITY, new String[] {VISIBILITY_PACKAGE, VISIBILITY_VALUE},
+                        SELECTION_ACCOUNTS_ID_BY_ACCOUNT, new String[] {account.name, account.type},
+                        null, null, null);
         try {
             while (cursor.moveToNext()) {
-                result.put(cursor.getInt(0), cursor.getInt(1));
+                result.put(cursor.getString(0), cursor.getInt(1));
             }
         } finally {
             cursor.close();
@@ -963,10 +972,10 @@
         return result;
     }
 
-    boolean deleteAccountVisibilityForUid(int uid) {
+    boolean deleteAccountVisibilityForPackage(String packageName) {
         SQLiteDatabase db = mDeDatabase.getWritableDatabase();
-        return db.delete(TABLE_VISIBILITY, VISIBILITY_UID + "=? ",
-                new String[] {Integer.toString(uid)}) > 0;
+        return db.delete(TABLE_VISIBILITY, VISIBILITY_PACKAGE + "=? ",
+                new String[] {packageName}) > 0;
     }
 
     long insertOrReplaceMetaAuthTypeAndUid(String authenticatorType, int uid) {
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
new file mode 100644
index 0000000..84e4ea9
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -0,0 +1,122 @@
+/*
+ * 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.server.am;
+
+import android.app.IInstrumentationWatcher;
+import android.app.IUiAutomationConnection;
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+import android.util.PrintWriterPrinter;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+class ActiveInstrumentation {
+    final ActivityManagerService mService;
+
+    // Class installed to instrument app
+    ComponentName mClass;
+
+    // All process names that should be instrumented
+    String[] mTargetProcesses;
+
+    // The application being instrumented
+    ApplicationInfo mTargetInfo;
+
+    // Where to save profiling
+    String mProfileFile;
+
+    // Who is waiting
+    IInstrumentationWatcher mWatcher;
+
+    // Connection to use the UI introspection APIs.
+    IUiAutomationConnection mUiAutomationConnection;
+
+    // As given to us
+    Bundle mArguments;
+
+    // Any intermediate results that have been collected.
+    Bundle mCurResults;
+
+    // Copy of instrumentationClass.
+    ComponentName mResultClass;
+
+    // Contains all running processes that have active instrumentation.
+    final ArrayList<ProcessRecord> mRunningProcesses = new ArrayList<>();
+
+    // Set to true when we have told the watcher the instrumentation is finished.
+    boolean mFinished;
+
+    ActiveInstrumentation(ActivityManagerService service) {
+        mService = service;
+    }
+
+    void removeProcess(ProcessRecord proc) {
+        mFinished = true;
+        mRunningProcesses.remove(proc);
+        if (mRunningProcesses.size() == 0) {
+            mService.mActiveInstrumentation.remove(this);
+        }
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("ActiveInstrumentation{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
+        sb.append(mClass.toShortString());
+        if (mFinished) {
+            sb.append(" FINISHED");
+        }
+        sb.append(" ");
+        sb.append(mRunningProcesses.size());
+        sb.append(" procs");
+        sb.append('}');
+        return sb.toString();
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mClass="); pw.print(mClass);
+        pw.print(" mFinished="); pw.println(mFinished);
+        pw.print(prefix); pw.println("mRunningProcesses:");
+        for (int i=0; i<mRunningProcesses.size(); i++) {
+            pw.print(prefix); pw.print("  #"); pw.print(i); pw.print(": ");
+            pw.println(mRunningProcesses.get(i));
+        }
+        pw.print(prefix); pw.print("mTargetProcesses=");
+        pw.println(Arrays.toString(mTargetProcesses));
+        pw.print(prefix); pw.print("mTargetInfo=");
+        pw.println(mTargetInfo);
+        if (mTargetInfo != null) {
+            mTargetInfo.dump(new PrintWriterPrinter(pw), prefix + "  ", 0);
+        }
+        if (mProfileFile != null) {
+            pw.print(prefix); pw.print("mProfileFile="); pw.println(mProfileFile);
+        }
+        if (mWatcher != null) {
+            pw.print(prefix); pw.print("mWatcher="); pw.println(mWatcher);
+        }
+        if (mUiAutomationConnection != null) {
+            pw.print(prefix); pw.print("mUiAutomationConnection=");
+            pw.println(mUiAutomationConnection);
+        }
+        pw.print(prefix); pw.print("mArguments=");
+        pw.println(mArguments);
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5655dc5..793a163 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 
 import java.io.FileDescriptor;
@@ -721,6 +723,39 @@
             if (notification == null) {
                 throw new IllegalArgumentException("null notification");
             }
+            // Instant apps need permission to create foreground services.
+            if (r.appInfo.isInstantApp()) {
+                final int mode = mAm.mAppOpsService.checkOperation(
+                        AppOpsManager.OP_INSTANT_APP_START_FOREGROUND,
+                        r.appInfo.uid,
+                        r.appInfo.packageName);
+                switch (mode) {
+                    case AppOpsManager.MODE_ALLOWED:
+                        break;
+                    case AppOpsManager.MODE_IGNORED:
+                        Slog.w(TAG, "Instant app " + r.appInfo.packageName
+                                + " does not have permission to create foreground services"
+                                + ", ignoring.");
+                        return;
+                    case AppOpsManager.MODE_ERRORED:
+                        throw new SecurityException("Instant app " + r.appInfo.packageName
+                                + " does not have permission to create foreground services");
+                    default:
+                        try {
+                            if (AppGlobals.getPackageManager().checkPermission(
+                                    android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
+                                    r.appInfo.packageName,
+                                    r.appInfo.uid) != PackageManager.PERMISSION_GRANTED) {
+                                throw new SecurityException("Instant app " + r.appInfo.packageName
+                                        + " does not have permission to create foreground"
+                                        + "services");
+                            }
+                        } catch (RemoteException e) {
+                            throw new SecurityException("Failed to check instant app permission." ,
+                                    e);
+                        }
+                }
+            }
             if (r.foregroundId != id) {
                 cancelForegroudNotificationLocked(r);
                 r.foregroundId = id;
@@ -1391,8 +1426,7 @@
         }
         if (r != null) {
             if (mAm.checkComponentPermission(r.permission,
-                    callingPid, callingUid, r.appInfo.uid, r.exported)
-                    != PackageManager.PERMISSION_GRANTED) {
+                    callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
                 if (!r.exported) {
                     Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                             + " from pid=" + callingPid
@@ -2775,16 +2809,15 @@
         return info;
     }
 
-    List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags) {
+    List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags,
+        int callingUid, boolean allowed) {
         ArrayList<ActivityManager.RunningServiceInfo> res
                 = new ArrayList<ActivityManager.RunningServiceInfo>();
 
-        final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         try {
-            if (ActivityManager.checkUidPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    uid) == PackageManager.PERMISSION_GRANTED) {
+            if (ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid)
+                == PERMISSION_GRANTED) {
                 int[] users = mAm.mUserController.getUsers();
                 for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
                     ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(users[ui]);
@@ -2802,16 +2835,20 @@
                     res.add(info);
                 }
             } else {
-                int userId = UserHandle.getUserId(uid);
+                int userId = UserHandle.getUserId(callingUid);
                 ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(userId);
                 for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
                     ServiceRecord sr = alls.valueAt(i);
-                    res.add(makeRunningServiceInfoLocked(sr));
+
+                    if (allowed || (sr.app != null && sr.app.uid == callingUid)) {
+                        res.add(makeRunningServiceInfoLocked(sr));
+                    }
                 }
 
                 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
                     ServiceRecord r = mRestartingServices.get(i);
-                    if (r.userId == userId) {
+                    if (r.userId == userId
+                        && (allowed || (r.app != null && r.app.uid == callingUid))) {
                         ActivityManager.RunningServiceInfo info =
                                 makeRunningServiceInfoLocked(r);
                         info.restarting = r.nextRestartTime;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 3c90f93..100d821 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -36,7 +36,7 @@
     private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
 
     private static final boolean DEFAULT_ENFORCE_BG_CHECK = SystemProperties.getBoolean(
-            "debug.bgcheck", false);
+            "debug.bgcheck", true);
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
 
     // Enforce background check on apps targeting O?
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ee1f28f..69a3a26 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -573,7 +573,9 @@
 
     final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter();
 
-    public IntentFirewall mIntentFirewall;
+    final ArrayList<ActiveInstrumentation> mActiveInstrumentation = new ArrayList<>();
+
+    public final IntentFirewall mIntentFirewall;
 
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
     // default action automatically.  Important for devices without direct input
@@ -699,18 +701,15 @@
         public AssistStructure structure = null;
         public AssistContent content = null;
         public Bundle receiverExtras;
-        public int resultCode;
 
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _resultCode,
-                int _userHandle) {
+                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
             receiver = _receiver;
             receiverExtras = _receiverExtras;
-            resultCode = _resultCode;
             userHandle = _userHandle;
         }
         @Override
@@ -1625,10 +1624,6 @@
     int mThumbnailHeight;
     float mFullscreenThumbnailScale;
 
-    /** The aspect ratio bounds of the PIP. */
-    float mMinPipAspectRatio;
-    float mMaxPipAspectRatio;
-
     final ServiceThread mHandlerThread;
     final MainHandler mHandler;
     final UiHandler mUiHandler;
@@ -2616,6 +2611,14 @@
         mPermissionReviewRequired = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_permissionReviewRequired);
 
+        mHandlerThread = new ServiceThread(TAG,
+                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
+        mHandlerThread.start();
+        mHandler = new MainHandler(mHandlerThread.getLooper());
+        mUiHandler = new UiHandler();
+
+        mConstants = new ActivityManagerConstants(this, mHandler);
+
         if (DEBUG_BACKGROUND_CHECK) {
             Slog.d(TAG, "Enforcing O+ bg restrictions: " + mConstants.ENFORCE_BG_CHECK);
             StringBuilder sb = new StringBuilder(200);
@@ -2627,14 +2630,6 @@
             Slog.d(TAG, sb.toString());
         }
 
-        mHandlerThread = new ServiceThread(TAG,
-                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
-        mHandlerThread.start();
-        mHandler = new MainHandler(mHandlerThread.getLooper());
-        mUiHandler = new UiHandler();
-
-        mConstants = new ActivityManagerConstants(this, mHandler);
-
         /* static; one-time init here */
         if (sKillHandler == null) {
             sKillThread = new ServiceThread(TAG + ":kill",
@@ -3926,7 +3921,7 @@
             aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
             ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                     aInfo.applicationInfo.uid, true);
-            if (app == null || app.instrumentationClass == null) {
+            if (app == null || app.instr == null) {
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                 mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
             }
@@ -5092,9 +5087,9 @@
 
         app.activities.clear();
 
-        if (app.instrumentationClass != null) {
+        if (app.instr != null) {
             Slog.w(TAG, "Crash of app " + app.processName
-                  + " running instrumentation " + app.instrumentationClass);
+                  + " running instrumentation " + app.instr.mClass);
             Bundle info = new Bundle();
             info.putString("shortMsg", "Process crashed.");
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
@@ -5227,7 +5222,7 @@
         // Clean up already done if the process has been re-started.
         if (app.pid == pid && app.thread != null &&
                 app.thread.asBinder() == thread.asBinder()) {
-            boolean doLowMem = app.instrumentationClass == null;
+            boolean doLowMem = app.instr == null;
             boolean doOomAdj = doLowMem;
             if (!app.killedByAm) {
                 Slog.i(TAG, "Process " + app.processName + " (pid " + pid
@@ -5331,7 +5326,8 @@
                     for (int pid : pids) {
                         if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
                         final long sime = SystemClock.elapsedRealtime();
-                        Debug.dumpNativeBacktraceToFile(pid, tracesPath);
+
+                        Debug.dumpNativeBacktraceToFileTimeout(pid, tracesPath, 10);
                         if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
                                 + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                     }
@@ -5568,7 +5564,7 @@
 
                 // Reset notification settings.
                 INotificationManager inm = NotificationManager.getService();
-                inm.clearData(packageName, pkgUidF);
+                inm.clearData(packageName, pkgUidF, uid == pkgUidF);
             } catch (RemoteException e) {
             }
         } finally {
@@ -6383,7 +6379,7 @@
             handleAppDiedLocked(app, willRestart, allowRestart);
             if (willRestart) {
                 removeLruProcessLocked(app);
-                addAppLocked(app.info, false, null /* ABI override */);
+                addAppLocked(app.info, null, false, null /* ABI override */);
             }
         } else {
             mRemovedProcesses.add(app);
@@ -6559,7 +6555,7 @@
                     mWaitForDebugger = mOrigWaitForDebugger;
                 }
             }
-            String profileFile = app.instrumentationProfileFile;
+            String profileFile = app.instr != null ? app.instr.mProfileFile : null;
             ParcelFileDescriptor profileFd = null;
             int samplingInterval = 0;
             boolean profileAutoStop = false;
@@ -6587,14 +6583,13 @@
                                 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
-            if (app.instrumentationClass != null) {
-                notifyPackageUse(app.instrumentationClass.getPackageName(),
+            if (app.instr != null) {
+                notifyPackageUse(app.instr.mClass.getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
             }
             if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
                     + processName + " with config " + getGlobalConfiguration());
-            ApplicationInfo appInfo = app.instrumentationInfo != null
-                    ? app.instrumentationInfo : app.info;
+            ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
             app.compat = compatibilityInfoForPackageLocked(appInfo);
             if (profileFd != null) {
                 profileFd = profileFd.dup();
@@ -6614,16 +6609,57 @@
                         .getSerial();
 //            }
 
+            // Check if this is a secondary process that should be incorporated into some
+            // currently active instrumentation.  (Note we do this AFTER all of the profiling
+            // stuff above because profiling can currently happen only in the primary
+            // instrumentation process.)
+            if (mActiveInstrumentation.size() > 0 && app.instr == null) {
+                for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--) {
+                    ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
+                    if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
+                        if (aInstr.mTargetProcesses.length == 0) {
+                            // This is the wildcard mode, where every process brought up for
+                            // the target instrumentation should be included.
+                            if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
+                                app.instr = aInstr;
+                                aInstr.mRunningProcesses.add(app);
+                            }
+                        } else {
+                            for (String proc : aInstr.mTargetProcesses) {
+                                if (proc.equals(app.processName)) {
+                                    app.instr = aInstr;
+                                    aInstr.mRunningProcesses.add(app);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
             checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
-            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
-                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
-                    app.instrumentationUiAutomationConnection, testMode,
-                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
-                    isRestrictedBackupMode || !normalMode, app.persistent,
-                    new Configuration(getGlobalConfiguration()), app.compat,
-                    getCommonServicesLocked(app.isolated),
-                    mCoreSettingsObserver.getCoreSettingsLocked(),
-                    buildSerial);
+            if (app.instr != null) {
+                thread.bindApplication(processName, appInfo, providers,
+                        app.instr.mClass,
+                        profilerInfo, app.instr.mArguments,
+                        app.instr.mWatcher,
+                        app.instr.mUiAutomationConnection, testMode,
+                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
+                        isRestrictedBackupMode || !normalMode, app.persistent,
+                        new Configuration(getGlobalConfiguration()), app.compat,
+                        getCommonServicesLocked(app.isolated),
+                        mCoreSettingsObserver.getCoreSettingsLocked(),
+                        buildSerial);
+            } else {
+                thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
+                        null, null, null, testMode,
+                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
+                        isRestrictedBackupMode || !normalMode, app.persistent,
+                        new Configuration(getGlobalConfiguration()), app.compat,
+                        getCommonServicesLocked(app.isolated),
+                        mCoreSettingsObserver.getCoreSettingsLocked(),
+                        buildSerial);
+            }
 
             checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
             updateLruProcessLocked(app, false, null);
@@ -7623,12 +7659,13 @@
                     r.pictureInPictureArgs.copyOnlySet(args);
                     final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
                     final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
-                    final Rect bounds = isValidPictureInPictureAspectRatio(aspectRatio)
-                            ? mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY, aspectRatio)
-                            : mWindowManager.getPictureInPictureDefaultBounds(DEFAULT_DISPLAY);
+                    final Rect bounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
+                            aspectRatio);
                     mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
                             bounds, true /* moveHomeStackToFront */);
-                    mStackSupervisor.getStack(PINNED_STACK_ID).setPictureInPictureActions(actions);
+                    final ActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
+                    stack.setPictureInPictureAspectRatio(aspectRatio);
+                    stack.setPictureInPictureActions(actions);
 
                     MetricsLogger.action(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_ENTERED,
                             r.supportsPictureInPictureWhilePausing);
@@ -7705,10 +7742,6 @@
         }
     }
 
-    private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
-        return mMinPipAspectRatio <= aspectRatio && aspectRatio <= mMaxPipAspectRatio;
-    }
-
     /**
      * Checks the state of the system and the activity associated with the given {@param token} to
      * verify that picture-in-picture is supported for that activity.
@@ -7739,10 +7772,15 @@
         }
 
         if (args.hasSetAspectRatio()
-                && !isValidPictureInPictureAspectRatio(args.getAspectRatio())) {
+                && !mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
+                        args.getAspectRatio())) {
+            final float minAspectRatio = mContext.getResources().getFloat(
+                    com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+            final float maxAspectRatio = mContext.getResources().getFloat(
+                    com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
             throw new IllegalArgumentException(String.format(caller
                     + ": Aspect ratio is too extreme (must be between %f and %f).",
-                            mMinPipAspectRatio, mMaxPipAspectRatio));
+                            minAspectRatio, maxAspectRatio));
         }
 
         if (args.hasSetActions()
@@ -8077,8 +8115,8 @@
     // of service-launch policy, allow those callers to proceed unrestricted.
     int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
         // Persistent app?  NB: expects that persistent uids are always active.
-        final UidRecord uidRec = mActiveUids.get(uid);
-        if (uidRec != null && uidRec.persistent) {
+        final UidRecord appIdRec = mActiveUids.get(UserHandle.getAppId(uid));
+        if (appIdRec != null && appIdRec.persistent) {
             if (DEBUG_BACKGROUND_CHECK) {
                 Slog.i(TAG, "App " + uid + "/" + packageName
                         + " is persistent; not restricted in background");
@@ -11595,7 +11633,7 @@
                         .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                 for (ApplicationInfo app : apps) {
                     if (!"android".equals(app.packageName)) {
-                        addAppLocked(app, false, null /* ABI override */);
+                        addAppLocked(app, null, false, null /* ABI override */);
                     }
                 }
             } catch (RemoteException ex) {
@@ -11783,17 +11821,18 @@
         return false;
     }
 
-    final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
+    final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
             String abiOverride) {
         ProcessRecord app;
         if (!isolated) {
-            app = getProcessRecordLocked(info.processName, info.uid, true);
+            app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
+                    info.uid, true);
         } else {
             app = null;
         }
 
         if (app == null) {
-            app = newProcessRecordLocked(info, null, isolated, 0);
+            app = newProcessRecordLocked(info, customProcess, isolated, 0);
             updateLruProcessLocked(app, false, null);
             updateOomAdjLocked();
         }
@@ -11814,7 +11853,8 @@
         }
         if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
             mPersistentStartingProcesses.add(app);
-            startProcessLocked(app, "added application", app.processName, abiOverride,
+            startProcessLocked(app, "added application",
+                    customProcess != null ? customProcess : app.processName, abiOverride,
                     null /* entryPoint */, null /* entryPointArgs */);
         }
 
@@ -12269,11 +12309,11 @@
         synchronized (this) {
             synchronized (mPidsSelfLocked) {
                 final int callingPid = Binder.getCallingPid();
-                ProcessRecord precessRecord = mPidsSelfLocked.get(callingPid);
-                if (precessRecord == null) {
+                ProcessRecord proc = mPidsSelfLocked.get(callingPid);
+                if (proc == null) {
                     throw new SecurityException("Unknown process: " + callingPid);
                 }
-                if (precessRecord.instrumentationUiAutomationConnection  == null) {
+                if (proc.instr == null || proc.instr.mUiAutomationConnection == null) {
                     throw new SecurityException("Only an instrumentation process "
                             + "with a UiAutomation can call setUserIsMonkey");
                 }
@@ -12330,7 +12370,7 @@
     }
 
     public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
-        if (r != null && (r.instrumentationClass != null || r.usingWrapper)) {
+        if (r != null && (r.instr != null || r.usingWrapper)) {
             return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
         }
         return KEY_DISPATCHING_TIMEOUT;
@@ -12391,7 +12431,7 @@
                     return false;
                 }
 
-                if (proc.instrumentationClass != null) {
+                if (proc.instr != null) {
                     Bundle info = new Bundle();
                     info.putString("shortMsg", "keyDispatchingTimedOut");
                     info.putString("longMsg", annotation);
@@ -12413,7 +12453,7 @@
     @Override
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
-                null, 0, null, true /* focused */, true /* newSessionId */,
+                null, null, true /* focused */, true /* newSessionId */,
                 UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
         if (pae == null) {
             return null;
@@ -12480,29 +12520,29 @@
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
             Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId) {
         return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
-                0, activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
+                activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
                 PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) != null;
     }
 
     @Override
     public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras,
-            int resultCode, IBinder activityToken) {
+            IBinder activityToken) {
         // NOTE: we could always use ActivityManager.ASSIST_CONTEXT_FULL and let ActivityThread
         // rely on the flags to decide whether the handleRequestAssistContextExtras() is for
         // auto-fill, but it's safer to explicitly use new AutoFill types, in case the Assist
         // requests use flags in the future as well (since their flags value might collide with the
         // auto-fill flag values).
         return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTO_FILL, null, null,
-                receiver, receiverExtras, resultCode, activityToken, true, true,
-                UserHandle.getCallingUserId(), null,
-                PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT) != null;
+                receiver, receiverExtras, activityToken, true, true, UserHandle.getCallingUserId(),
+                null, PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT) != null;
     }
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
-            IResultReceiver receiver, Bundle receiverExtras, int resultCode, IBinder activityToken,
+            IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
             boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
+
         synchronized (this) {
             ActivityRecord activity = getFocusedStack().topActivity();
             if (activity == null) {
@@ -12538,8 +12578,10 @@
             }
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
+
             pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
-                    resultCode, userHandle);
+                    userHandle);
+
             // Increment the sessionId if necessary
             if (newSessionId) {
                 mViSessionId++;
@@ -12622,15 +12664,11 @@
                 sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
                 sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
                         pae.receiverExtras);
-                IBinder cb = extras.getBinder(AutoFillService.KEY_CALLBACK);
-                if (cb != null) {
-                    sendBundle.putBinder(AutoFillService.KEY_CALLBACK, cb);
-                }
             }
         }
         if (sendReceiver != null) {
             try {
-                sendReceiver.send(pae.resultCode, sendBundle);
+                sendReceiver.send(0, sendBundle);
             } catch (RemoteException e) {
             }
             return;
@@ -12655,7 +12693,7 @@
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
             Bundle args) {
-        return enqueueAssistContext(requestType, intent, hint, null, null, 0, null,
+        return enqueueAssistContext(requestType, intent, hint, null, null, null,
                 true /* focused */, true /* newSessionId */, userHandle, args,
                 PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
     }
@@ -13425,10 +13463,6 @@
                     com.android.internal.R.dimen.thumbnail_width);
             mThumbnailHeight = res.getDimensionPixelSize(
                     com.android.internal.R.dimen.thumbnail_height);
-            mMinPipAspectRatio = res.getFloat(
-                    com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
-            mMaxPipAspectRatio = res.getFloat(
-                    com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
             mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
                     com.android.internal.R.string.config_appsNotReportingCrashes));
             mUserController.mUserSwitchUiEnabled = !res.getBoolean(
@@ -14901,8 +14935,31 @@
                     printed = true;
                     needSep = true;
                 }
-                pw.println(String.format("%sIsolated #%2d: %s",
-                        "    ", i, r.toString()));
+                pw.print("    Isolated #"); pw.print(i); pw.print(": ");
+                pw.println(r);
+            }
+        }
+
+        if (mActiveInstrumentation.size() > 0) {
+            boolean printed = false;
+            for (int i=0; i<mActiveInstrumentation.size(); i++) {
+                ActiveInstrumentation ai = mActiveInstrumentation.get(i);
+                if (dumpPackage != null && !ai.mClass.getPackageName().equals(dumpPackage)
+                        && !ai.mTargetInfo.packageName.equals(dumpPackage)) {
+                    continue;
+                }
+                if (!printed) {
+                    if (needSep) {
+                        pw.println();
+                    }
+                    pw.println("  Active instrumentation:");
+                    printedAnything = true;
+                    printed = true;
+                    needSep = true;
+                }
+                pw.print("    Instrumentation #"); pw.print(i); pw.print(": ");
+                pw.println(ai);
+                ai.dump(pw, "      ");
             }
         }
 
@@ -17400,7 +17457,11 @@
             int flags) {
         enforceNotIsolatedCaller("getServices");
         synchronized (this) {
-            return mServices.getRunningServiceInfoLocked(maxNum, flags);
+            final int callingUid = Binder.getCallingUid();
+            final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
+                callingUid);
+
+            return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid, allowed);
         }
     }
 
@@ -19046,18 +19107,35 @@
                 throw new SecurityException(msg);
             }
 
+            ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
+            activeInstr.mClass = className;
+            String defProcess = ai.processName;;
+            if (ii.targetProcess == null) {
+                activeInstr.mTargetProcesses = new String[]{ai.processName};
+            } else if (ii.targetProcess.equals("*")) {
+                activeInstr.mTargetProcesses = new String[0];
+            } else {
+                activeInstr.mTargetProcesses = ii.targetProcess.split(",");
+                defProcess = activeInstr.mTargetProcesses[0];
+            }
+            activeInstr.mTargetInfo = ai;
+            activeInstr.mProfileFile = profileFile;
+            activeInstr.mArguments = arguments;
+            activeInstr.mWatcher = watcher;
+            activeInstr.mUiAutomationConnection = uiAutomationConnection;
+            activeInstr.mResultClass = className;
+
             final long origId = Binder.clearCallingIdentity();
             // Instrumentation can kill and relaunch even persistent processes
             forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
                     "start instr");
-            ProcessRecord app = addAppLocked(ai, false, abiOverride);
-            app.instrumentationClass = className;
-            app.instrumentationInfo = ai;
-            app.instrumentationProfileFile = profileFile;
-            app.instrumentationArguments = arguments;
-            app.instrumentationWatcher = watcher;
-            app.instrumentationUiAutomationConnection = uiAutomationConnection;
-            app.instrumentationResultClass = className;
+            ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride);
+            app.instr = activeInstr;
+            activeInstr.mFinished = false;
+            activeInstr.mRunningProcesses.add(app);
+            if (!mActiveInstrumentation.contains(activeInstr)) {
+                mActiveInstrumentation.add(activeInstr);
+            }
             Binder.restoreCallingIdentity(origId);
         }
 
@@ -19084,24 +19162,70 @@
         }
     }
 
+    void addInstrumentationResultsLocked(ProcessRecord app, Bundle results) {
+        if (app.instr == null) {
+            Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
+            return;
+        }
+
+        if (!app.instr.mFinished && results != null) {
+            if (app.instr.mCurResults == null) {
+                app.instr.mCurResults = new Bundle(results);
+            } else {
+                app.instr.mCurResults.putAll(results);
+            }
+        }
+    }
+
+    public void addInstrumentationResults(IApplicationThread target, Bundle results) {
+        int userId = UserHandle.getCallingUserId();
+        // Refuse possible leaked file descriptors
+        if (results != null && results.hasFileDescriptors()) {
+            throw new IllegalArgumentException("File descriptors passed in Intent");
+        }
+
+        synchronized(this) {
+            ProcessRecord app = getRecordForAppLocked(target);
+            if (app == null) {
+                Slog.w(TAG, "addInstrumentationResults: no app for " + target);
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            addInstrumentationResultsLocked(app, results);
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
-        if (app.instrumentationWatcher != null) {
-            mInstrumentationReporter.reportFinished(app.instrumentationWatcher,
-                    app.instrumentationClass, resultCode, results);
+        if (app.instr == null) {
+            Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
+            return;
         }
 
-        // Can't call out of the system process with a lock held, so post a message.
-        if (app.instrumentationUiAutomationConnection != null) {
-            mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
-                    app.instrumentationUiAutomationConnection).sendToTarget();
+        if (!app.instr.mFinished) {
+            if (app.instr.mWatcher != null) {
+                Bundle finalResults = app.instr.mCurResults;
+                if (finalResults != null) {
+                    if (app.instr.mCurResults != null && results != null) {
+                        finalResults.putAll(results);
+                    }
+                } else {
+                    finalResults = results;
+                }
+                mInstrumentationReporter.reportFinished(app.instr.mWatcher,
+                        app.instr.mClass, resultCode, finalResults);
+            }
+
+            // Can't call out of the system process with a lock held, so post a message.
+            if (app.instr.mUiAutomationConnection != null) {
+                mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
+                        app.instr.mUiAutomationConnection).sendToTarget();
+            }
+            app.instr.mFinished = true;
         }
 
-        app.instrumentationWatcher = null;
-        app.instrumentationUiAutomationConnection = null;
-        app.instrumentationClass = null;
-        app.instrumentationInfo = null;
-        app.instrumentationProfileFile = null;
-        app.instrumentationArguments = null;
+        app.instr.removeProcess(app);
+        app.instr = null;
 
         forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
                 "finished inst");
@@ -19884,7 +20008,7 @@
             app.adjType = "top-activity";
             foregroundActivities = true;
             procState = PROCESS_STATE_CUR_TOP;
-        } else if (app.instrumentationClass != null) {
+        } else if (app.instr != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -21973,7 +22097,7 @@
                     mRemovedProcesses.remove(i);
 
                     if (app.persistent) {
-                        addAppLocked(app.info, false, null /* ABI override */);
+                        addAppLocked(app.info, null, false, null /* ABI override */);
                     }
                 }
             }
@@ -22605,13 +22729,6 @@
         }
 
         @Override
-        public IBinder getTopVisibleActivity(int uid) {
-            synchronized (ActivityManagerService.this) {
-                return mStackSupervisor.getTopVisibleActivity(uid);
-            }
-        }
-
-        @Override
         public void notifyDockedStackMinimizedChanged(boolean minimized) {
             synchronized (ActivityManagerService.this) {
                 mStackSupervisor.setDockedStackMinimized(minimized);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 3573b8b..58c17eb 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -30,6 +30,7 @@
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
@@ -44,7 +45,10 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
 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 com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -79,6 +83,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
@@ -2007,7 +2012,8 @@
                         + ", newGlobalConfig=" + newGlobalConfig
                         + ", newTaskMergedOverrideConfig=" + newTaskMergedOverrideConfig);
 
-        if ((changes&(~info.getRealConfigChanged())) != 0 || forceNewConfig) {
+        if (shouldRelaunchLocked(changes, newGlobalConfig, newTaskMergedOverrideConfig)
+                || forceNewConfig) {
             // Aha, the activity isn't handling the change, so DIE DIE DIE.
             configChangeFlags |= changes;
             startFreezingScreenLocked(app, globalChanges);
@@ -2058,6 +2064,27 @@
         return true;
     }
 
+    /**
+     * When assessing a configuration change, decide if the changes flags and the new configurations
+     * should cause the Activity to relaunch.
+     */
+    private boolean shouldRelaunchLocked(int changes, Configuration newGlobalConfig,
+            Configuration newTaskMergedOverrideConfig) {
+        int configChanged = info.getRealConfigChanged();
+
+        // Override for apps targeting pre-O sdks
+        // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode
+        // to the config change.
+        // For O and later, apps will be required to add configChanges="uimode" to their manifest.
+        if (appInfo.targetSdkVersion < O
+                && requestedVrComponent != null
+                && (isInVrUiMode(newGlobalConfig) || isInVrUiMode(newTaskMergedOverrideConfig))) {
+            configChanged |= CONFIG_UI_MODE;
+        }
+
+        return (changes&(~configChanged)) != 0;
+    }
+
     private static int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
             Configuration oldTaskOverride) {
         // If we went from full-screen to non-full-screen, make sure to use the correct
@@ -2294,6 +2321,10 @@
         }
     }
 
+    private static boolean isInVrUiMode(Configuration config) {
+        return (config.uiMode & Configuration.UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
+    }
+
     @Override
     public String toString() {
         if (stringName != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 10d108b..104fc6a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -544,6 +544,10 @@
         mWindowContainerController.setPictureInPictureAspectRatio(aspectRatio);
     }
 
+    void setPictureInPictureActions(List<RemoteAction> actions) {
+        mWindowContainerController.setPictureInPictureActions(actions);
+    }
+
     void getStackDockedModeBounds(Rect outBounds, Rect outTempBounds, Rect outTempInsetBounds,
             boolean ignoreVisibility) {
         mWindowContainerController.getStackDockedModeBounds(outBounds, outTempBounds,
@@ -554,10 +558,6 @@
         mWindowContainerController.prepareFreezingTaskBounds();
     }
 
-    void setPictureInPictureActions(List<RemoteAction> actions) {
-        mWindowContainerController.setPictureInPictureActions(actions);
-    }
-
     void getWindowContainerBounds(Rect outBounds) {
         if (mWindowContainerController != null) {
             mWindowContainerController.getBounds(outBounds);
@@ -1554,38 +1554,6 @@
         final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
         final int focusedStackId = focusedStack.mStackId;
 
-        final TaskRecord topFocusedTask = focusedStack.topTask();
-        final boolean isOnTopLauncherFocused = topFocusedTask != null &&
-                topFocusedTask.isOnTopLauncher();
-        if (isOnTopLauncherFocused) {
-            // When an on-top launcher is focused, we should find out whether the freeform stack or
-            // the fullscreen stack appears first underneath and has activities to show, and then
-            // make it visible.
-            boolean behindFullscreenOrFreeForm = false;
-            for (int stackBehindFocusedIndex = mStacks.indexOf(focusedStack) - 1;
-                 stackBehindFocusedIndex >= 0; stackBehindFocusedIndex--) {
-                ActivityStack stack = mStacks.get(stackBehindFocusedIndex);
-                if ((stack.mStackId == FREEFORM_WORKSPACE_STACK_ID
-                        || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID)
-                        && stack.topRunningActivityLocked() != null) {
-                    if (stackIndex == stackBehindFocusedIndex) {
-                        return !behindFullscreenOrFreeForm ? STACK_VISIBLE : STACK_INVISIBLE;
-                    }
-                    behindFullscreenOrFreeForm = true;
-                }
-            }
-        }
-        // If an on-top launcher is on the top of the home stack but the home stack is not focused,
-        // then the whole stack should be invisible.
-        TaskRecord topTask = topTask();
-        if (mStackId != focusedStackId && topTask != null && topTask.isOnTopLauncher()) {
-            // We're here mostly because the on-top launcher didn't have a chance to move itself to
-            // back. We should move it to back as soon as possible to avoid other activities
-            // returning to it or other visibility issues.
-            moveTaskToBackLocked(topTask.taskId);
-            return STACK_INVISIBLE;
-        }
-
         if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID
                 && hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(focusedStackId)
                 && !focusedStack.topActivity().fullscreen) {
@@ -1790,28 +1758,7 @@
                     // status of an activity in a previous task affects other.
                     behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
                 } else if (mStackId == HOME_STACK_ID) {
-                    if (task.isOnTopLauncher()) {
-                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "On-top launcher: at " + task
-                                + " stackInvisible=" + stackInvisible
-                                + " behindFullscreenActivity=" + behindFullscreenActivity);
-                        // When an on-top launcher is visible, (e.g. it's on the top of the home stack),
-                        // other tasks in the home stack could be visible if and only if:
-                        // - some app is running in the docked stack;
-                        // - no app is running in either the fullscreen stack or the freefrom stack.
-                        final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
-                        final ActivityStack fullscreenStack = mStackSupervisor.getStack(
-                                FULLSCREEN_WORKSPACE_STACK_ID);
-                        final ActivityStack freeformStack = mStackSupervisor.getStack(
-                                FREEFORM_WORKSPACE_STACK_ID);
-                        final boolean dockedStackEmpty = dockedStack == null ||
-                                dockedStack.topRunningActivityLocked() == null;
-                        final boolean fullscreenStackEmpty = fullscreenStack == null ||
-                                fullscreenStack.topRunningActivityLocked() == null;
-                        final boolean freeformStackEmpty = freeformStack == null ||
-                                freeformStack.topRunningActivityLocked() == null;
-                        behindFullscreenActivity = dockedStackEmpty || !fullscreenStackEmpty ||
-                                !freeformStackEmpty;
-                    } else if (task.isHomeTask()) {
+                    if (task.isHomeTask()) {
                         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
                                 + " stackInvisible=" + stackInvisible
                                 + " behindFullscreenActivity=" + behindFullscreenActivity);
@@ -2699,14 +2646,7 @@
             ActivityStack lastStack = mStackSupervisor.getLastStack();
             final boolean fromHomeOrRecents = lastStack.isHomeOrRecentsStack();
             final TaskRecord topTask = lastStack.topTask();
-            final boolean fromOnTopLauncher = topTask != null && topTask.isOnTopLauncher();
-            if (fromOnTopLauncher) {
-                // Since an on-top launcher will is moved to back when tasks are launched from it,
-                // those tasks should first try to return to a non-home activity.
-                // This also makes sure that non-home activities are visible under a transparent
-                // non-home activity.
-                task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
-            } else if (!isHomeOrRecentsStack() && (fromHomeOrRecents || topTask() != task)) {
+            if (!isHomeOrRecentsStack() && (fromHomeOrRecents || topTask() != task)) {
                 // If it's a last task over home - we default to keep its return to type not to
                 // make underlying task focused when this one will be finished.
                 int returnToType = isLastTaskOverHome
@@ -4404,23 +4344,6 @@
         if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
 
         if (mStackId == HOME_STACK_ID && topTask().isHomeTask()) {
-            if (topTask().isOnTopLauncher()) {
-                // An on-top launcher doesn't affect the visibility of activities on other stacks
-                // behind it. So if we're moving an on-top launcher to the back, we want to move the
-                // focus to the next focusable stack and resume an activity there.
-                // Besides, when the docked stack is visible, we should also move the home stack to
-                // the back to avoid the recents pops up on top of a fullscreen or freeform
-                // activity.
-
-                // Move the home stack to back.
-                moveToBack(topTask());
-
-                // Resume an activity in the next focusable stack.
-                adjustFocusToNextFocusableStackLocked("moveTaskToBack");
-                mStackSupervisor.resumeFocusedStackTopActivityLocked();
-                return true;
-            }
-
             // For the case where we are moving the home task back and there is an activity visible
             // behind it on the fullscreen stack, we want to move the focus to the visible behind
             // activity to maintain order with what the user is seeing.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index da7dc7d..e954363 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4913,24 +4913,4 @@
         }
         return topActivityTokens;
     }
-
-    public IBinder getTopVisibleActivity(int uid) {
-        // TODO(b/33197203): get rid of DEFAULT_DISPLAY here?. Used in
-        // VoiceInteractionManagerServiceImpl#showSessionLocked.
-        final ActivityDisplay display = mActivityDisplays.get(DEFAULT_DISPLAY);
-        if (display == null) {
-            return null;
-        }
-        final ArrayList<ActivityStack> stacks = display.mStacks;
-        for (int i = stacks.size() - 1; i >= 0; i--) {
-            ActivityStack stack = stacks.get(i);
-            if (stack.getStackVisibilityLocked(null) == ActivityStack.STACK_VISIBLE) {
-                ActivityRecord top = stack.topActivity();
-                if (top != null && stack == mFocusedStack && top.app.uid == uid) {
-                    return top.appToken;
-                }
-            }
-        }
-        return null;
-    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index f5874af..d1606b4 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1498,15 +1498,7 @@
 
     private void updateTaskReturnToType(
             TaskRecord task, int launchFlags, ActivityStack focusedStack) {
-        if (focusedStack != null && focusedStack.isHomeOrRecentsStack()
-                && focusedStack.topTask() != null && focusedStack.topTask().isOnTopLauncher()) {
-            // Since an on-top launcher will is moved to back when tasks are launched from it,
-            // those tasks should first try to return to a non-home activity.
-            // This also makes sure that non-home activities are visible under a transparent
-            // non-home activity.
-            task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
-            return;
-        } else if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+        if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                 == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
             // Caller wants to appear on home activity.
             task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 384f2f8..36a913f 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -357,7 +357,7 @@
              * If this process was running instrumentation, finish now - it will be handled in
              * {@link ActivityManagerService#handleAppDiedLocked}.
              */
-            if (r != null && r.instrumentationClass != null) {
+            if (r != null && r.instr != null) {
                 return;
             }
 
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 49fe79c..356781f 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -135,13 +135,7 @@
     int lruSeq;                 // Sequence id for identifying LRU update cycles
     CompatibilityInfo compat;   // last used compatibility mode
     IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
-    ComponentName instrumentationClass;// class installed to instrument app
-    ApplicationInfo instrumentationInfo; // the application being instrumented
-    String instrumentationProfileFile; // where to save profiling
-    IInstrumentationWatcher instrumentationWatcher; // who is waiting
-    IUiAutomationConnection instrumentationUiAutomationConnection; // Connection to use the UI introspection APIs.
-    Bundle instrumentationArguments;// as given to us
-    ComponentName instrumentationResultClass;// copy of instrumentationClass
+    ActiveInstrumentation instr;// Set to currently active instrumentation running in process
     boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
     final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
     long lastWakeTime;          // How long proc held wake lock at last check
@@ -248,19 +242,8 @@
             pw.println("}");
         }
         pw.print(prefix); pw.print("compat="); pw.println(compat);
-        if (instrumentationClass != null || instrumentationProfileFile != null
-                || instrumentationArguments != null) {
-            pw.print(prefix); pw.print("instrumentationClass=");
-                    pw.print(instrumentationClass);
-                    pw.print(" instrumentationProfileFile=");
-                    pw.println(instrumentationProfileFile);
-            pw.print(prefix); pw.print("instrumentationArguments=");
-                    pw.println(instrumentationArguments);
-            pw.print(prefix); pw.print("instrumentationInfo=");
-                    pw.println(instrumentationInfo);
-            if (instrumentationInfo != null) {
-                instrumentationInfo.dump(new PrintWriterPrinter(pw), prefix + "  ");
-            }
+        if (instr != null) {
+            pw.print(prefix); pw.print("instr="); pw.println(instr);
         }
         pw.print(prefix); pw.print("thread="); pw.println(thread);
         pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9e09cbb..e237e41 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -75,7 +75,6 @@
 import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
@@ -191,17 +190,15 @@
 
     int mResizeMode;        // The resize mode of this task and its activities.
                             // Based on the {@link ActivityInfo#resizeMode} of the root activity.
-    boolean mSupportsPictureInPicture;  // Whether or not this task and its activities support PiP.
-            // Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root
-            // activity.
+    private boolean mSupportsPictureInPicture;  // Whether or not this task and its activities
+            // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag
+            // of the root activity.
     boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
                                      // changes on a temporary basis.
     private int mLockTaskMode;  // Which tasklock mode to launch this task in. One of
                                 // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
     private boolean mPrivileged;    // The root activity application of this task holds
                                     // privileged permissions.
-    private boolean mIsOnTopLauncher; // Whether this task is an on-top launcher. See
-                                      // android.R.attr#onTopLauncher.
 
     /** Can't be put in lockTask mode. */
     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
@@ -424,8 +421,8 @@
         final Configuration overrideConfig = getOverrideConfiguration();
         mWindowContainerController = new TaskWindowContainerController(taskId, this,
                 getStack().getWindowContainerController(), userId, bounds, overrideConfig,
-                mResizeMode, mSupportsPictureInPicture, isHomeTask(), isOnTopLauncher(),
-                onTop, showForAllUsers, lastTaskDescription);
+                mResizeMode, mSupportsPictureInPicture, isHomeTask(), onTop, showForAllUsers,
+                lastTaskDescription);
     }
 
     void removeWindowContainer() {
@@ -688,7 +685,6 @@
         }
         mResizeMode = info.resizeMode;
         mSupportsPictureInPicture = info.supportsPictureInPicture();
-        mIsOnTopLauncher = (info.flags & FLAG_ON_TOP_LAUNCHER) != 0;
         mLockTaskMode = info.lockTaskLaunchMode;
         mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
         setLockTaskAuth();
@@ -1335,7 +1331,7 @@
      * @param bounds The bounds to be tested.
      * @return True if the requested bounds are okay for a resizing request.
      */
-    boolean canResizeToBounds(Rect bounds) {
+    private boolean canResizeToBounds(Rect bounds) {
         if (bounds == null || getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
             // Note: If not on the freeform workspace, we ignore the bounds.
             return true;
@@ -1348,10 +1344,6 @@
                 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
     }
 
-    boolean isOnTopLauncher() {
-        return isHomeTask() && mIsOnTopLauncher;
-    }
-
     /**
      * Find the activity in the history stack within the given task.  Returns
      * the index within the history at which it's found, or < 0 if not found.
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index a1c5653..b4feef3 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -49,11 +49,18 @@
      * that they lost focus.
      */
     static final boolean ENFORCE_DUCKING = false;
+    /**
+     * set to true so the framework enforces muting media/game itself when the device is ringing
+     * or in a call.
+     */
+    static final boolean ENFORCE_MUTING_FOR_RING_OR_CALL = true;
 
     private final Context mContext;
     private final AppOpsManager mAppOps;
     private PlayerFocusEnforcer mFocusEnforcer; // never null
 
+    private boolean mRingOrCallActive = false;
+
     protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) {
         mContext = cntxt;
         mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
@@ -78,6 +85,16 @@
         mFocusEnforcer.unduckPlayers(winner);
     }
 
+    @Override
+    public void mutePlayersForCall(int[] usagesToMute) {
+        mFocusEnforcer.mutePlayersForCall(usagesToMute);
+    }
+
+    @Override
+    public void unmutePlayersForCall() {
+        mFocusEnforcer.unmutePlayersForCall();
+    }
+
     //==========================================================================================
     // AudioFocus
     //==========================================================================================
@@ -139,7 +156,9 @@
                 stackIterator.next().dump(pw);
             }
         }
-        pw.println("\n Notify on duck: " + mNotifyFocusOwnerOnDuck +"\n");
+        pw.println("\n");
+        pw.println(" Notify on duck:  " + mNotifyFocusOwnerOnDuck + "\n");
+        pw.println(" In ring or call: " + mRingOrCallActive + "\n");
     }
 
     /**
@@ -401,6 +420,18 @@
     }
 
     /**
+     * Delay after entering ringing or call mode after which the framework will mute streams
+     * that are still playing.
+     */
+    private static final int RING_CALL_MUTING_ENFORCEMENT_DELAY_MS = 100;
+
+    /**
+     * Usages to mute when the device rings or is in a call
+     */
+    private final static int[] USAGES_TO_MUTE_IN_RING_OR_CALL =
+        { AudioAttributes.USAGE_MEDIA, AudioAttributes.USAGE_GAME };
+
+    /**
      * Return the volume ramp time expected before playback with the given AudioAttributes would
      * start after gaining audio focus.
      * @param attr attributes of the sound about to start playing
@@ -452,6 +483,10 @@
         }
 
         synchronized(mAudioFocusLock) {
+            boolean enteringRingOrCall = !mRingOrCallActive
+                    & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
+            if (enteringRingOrCall) { mRingOrCallActive = true; }
+
             boolean focusGrantDelayed = false;
             if (!canReassignAudioFocus()) {
                 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
@@ -523,6 +558,9 @@
             notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
 
+            if (ENFORCE_MUTING_FOR_RING_OR_CALL & enteringRingOrCall) {
+                runAudioCheckerForRingOrCallAsync(true/*enteringRingOrCall*/);
+            }
         }//synchronized(mAudioFocusLock)
 
         return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
@@ -539,7 +577,15 @@
         try {
             // this will take care of notifying the new focus owner if needed
             synchronized(mAudioFocusLock) {
+                boolean exitingRingOrCall = mRingOrCallActive
+                        & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
+                if (exitingRingOrCall) { mRingOrCallActive = false; }
+
                 removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/);
+
+                if (ENFORCE_MUTING_FOR_RING_OR_CALL & exitingRingOrCall) {
+                    runAudioCheckerForRingOrCallAsync(false/*enteringRingOrCall*/);
+                }
             }
         } catch (java.util.ConcurrentModificationException cme) {
             // Catching this exception here is temporary. It is here just to prevent
@@ -559,4 +605,26 @@
         }
     }
 
+    private void runAudioCheckerForRingOrCallAsync(final boolean enteringRingOrCall) {
+        new Thread() {
+            public void run() {
+                if (enteringRingOrCall) {
+                    try {
+                        Thread.sleep(RING_CALL_MUTING_ENFORCEMENT_DELAY_MS);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+                synchronized (mAudioFocusLock) {
+                    // since the new thread starting running the state could have changed, so
+                    // we need to check again mRingOrCallActive, not enteringRingOrCall
+                    if (mRingOrCallActive) {
+                        mFocusEnforcer.mutePlayersForCall(USAGES_TO_MUTE_IN_RING_OR_CALL);
+                    } else {
+                        mFocusEnforcer.unmutePlayersForCall();
+                    }
+                }
+            }
+        }.start();
+    }
 }
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 816d5fe..3f8bbe5 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -46,7 +46,7 @@
         implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
 
     public final static String TAG = "AudioService.PlaybackActivityMonitor";
-    private final static boolean DEBUG = true;
+    private final static boolean DEBUG = false;
 
     private ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
     // a public client is one that needs an anonymized version of the playback configurations, we
@@ -147,6 +147,11 @@
             for (int piid : mDuckedPlayers) {
                 pw.println(" " + piid);
             }
+            // players muted due to the device ringing or being in a call
+            pw.println("\n  muted player piids:");
+            for (int piid : mMutedPlayers) {
+                pw.println(" " + piid);
+            }
         }
     }
 
@@ -231,6 +236,7 @@
     //=================================================================
     // PlayerFocusEnforcer implementation
     private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
+    private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
 
     @Override
     public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
@@ -290,9 +296,9 @@
                         && winner.hasSameUid(apc.getClientUid())) {
                     try {
                         if (DEBUG) { Log.v(TAG, "unducking player" + piid); }
+                        mDuckedPlayers.remove(new Integer(piid));
                         //FIXME just a test before we have VolumeShape
                         apc.getPlayerProxy().setPan(0.0f);
-                        mDuckedPlayers.remove(new Integer(piid));
                     } catch (Exception e) {
                         Log.e(TAG, "Error unducking player " + piid, e);
                     }
@@ -303,6 +309,65 @@
         }
     }
 
+    @Override
+    public void mutePlayersForCall(int[] usagesToMute) {
+        if (DEBUG) {
+            String log = new String("mutePlayersForCall: usages=");
+            for (int usage : usagesToMute) { log += " " + usage; }
+            Log.v(TAG, log);
+        }
+        synchronized (mPlayerLock) {
+            final Set<Integer> piidSet = mPlayers.keySet();
+            final Iterator<Integer> piidIterator = piidSet.iterator();
+            // find which players to mute
+            while (piidIterator.hasNext()) {
+                final Integer piid = piidIterator.next();
+                final AudioPlaybackConfiguration apc = mPlayers.get(piid);
+                final int playerUsage = apc.getAudioAttributes().getUsage();
+                boolean mute = false;
+                for (int usageToMute : usagesToMute) {
+                    if (playerUsage == usageToMute) {
+                        mute = true;
+                        break;
+                    }
+                }
+                if (mute) {
+                    try {
+                        if (DEBUG) { Log.v(TAG, "muting player" + piid); }
+                        apc.getPlayerProxy().setVolume(0.0f);
+                        mMutedPlayers.add(piid);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Error muting player " + piid, e);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void unmutePlayersForCall() {
+        if (DEBUG) {
+            Log.v(TAG, "unmutePlayersForCall()");
+        }
+        synchronized (mPlayerLock) {
+            if (mMutedPlayers.isEmpty()) {
+                return;
+            }
+            for (int piid : mMutedPlayers) {
+                final AudioPlaybackConfiguration apc = mPlayers.get(piid);
+                if (apc != null) {
+                    try {
+                        if (DEBUG) { Log.v(TAG, "unmuting player" + piid); }
+                        apc.getPlayerProxy().setVolume(1.0f);
+                        mMutedPlayers.remove(new Integer(piid));
+                    } catch (Exception e) {
+                        Log.e(TAG, "Error unmuting player " + piid, e);
+                    }
+                }
+            }
+        }
+    }
+
     //=================================================================
     // Track playback activity listeners
 
diff --git a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
index acb4f0d..0733eca 100644
--- a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
+++ b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
@@ -28,4 +28,8 @@
     public boolean duckPlayers(FocusRequester winner, FocusRequester loser);
 
     public void unduckPlayers(FocusRequester winner);
+
+    public void mutePlayersForCall(int[] usagesToMute);
+
+    public void unmutePlayersForCall();
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 3da49d8..168744b 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -18,9 +18,6 @@
 
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.twilight.TwilightListener;
-import com.android.server.twilight.TwilightManager;
-import com.android.server.twilight.TwilightState;
 
 import android.annotation.Nullable;
 import android.hardware.Sensor;
@@ -55,9 +52,6 @@
     // non-zero, which in turn ensures that the total weight is non-zero.
     private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
 
-    // Specifies the maximum magnitude of the time of day adjustment.
-    private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1f;
-
     // Debounce for sampling user-initiated changes in display brightness to ensure
     // the user is satisfied with the result before storing the sample.
     private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
@@ -74,9 +68,6 @@
     // The light sensor, or null if not available or needed.
     private final Sensor mLightSensor;
 
-    // The twilight service.
-    private final TwilightManager mTwilight;
-
     // The auto-brightness spline adjustment.
     // The brightness values have been scaled to a range of 0..1.
     private final Spline mScreenAutoBrightnessSpline;
@@ -186,8 +177,6 @@
     private int mBrightnessAdjustmentSampleOldBrightness;
     private float mBrightnessAdjustmentSampleOldGamma;
 
-    private boolean mUseTwilight;
-
     public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
             SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
             int brightnessMin, int brightnessMax, float dozeScaleFactor,
@@ -196,7 +185,6 @@
             int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
             HysteresisLevels dynamicHysteresis) {
         mCallbacks = callbacks;
-        mTwilight = LocalServices.getService(TwilightManager.class);
         mSensorManager = sensorManager;
         mScreenAutoBrightnessSpline = autoBrightnessSpline;
         mScreenBrightnessRangeMinimum = brightnessMin;
@@ -233,7 +221,7 @@
     }
 
     public void configure(boolean enable, float adjustment, boolean dozing,
-            boolean userInitiatedChange, boolean useTwilight) {
+            boolean userInitiatedChange) {
         // While dozing, the application processor may be suspended which will prevent us from
         // receiving new information from the light sensor. On some devices, we may be able to
         // switch to a wake-up light sensor instead but for now we will simply disable the sensor
@@ -242,7 +230,6 @@
         mDozing = dozing;
         boolean changed = setLightSensorEnabled(enable && !dozing);
         changed |= setScreenAutoBrightnessAdjustment(adjustment);
-        changed |= setUseTwilight(useTwilight);
         if (changed) {
             updateAutoBrightness(false /*sendUpdate*/);
         }
@@ -251,17 +238,6 @@
         }
     }
 
-    private boolean setUseTwilight(boolean useTwilight) {
-        if (mUseTwilight == useTwilight) return false;
-        if (useTwilight) {
-            mTwilight.registerListener(mTwilightListener, mHandler);
-        } else {
-            mTwilight.unregisterListener(mTwilightListener);
-        }
-        mUseTwilight = useTwilight;
-        return true;
-    }
-
     public void dump(PrintWriter pw) {
         pw.println();
         pw.println("Automatic Brightness Controller Configuration:");
@@ -276,7 +252,6 @@
         pw.println();
         pw.println("Automatic Brightness Controller State:");
         pw.println("  mLightSensor=" + mLightSensor);
-        pw.println("  mTwilight.getLastTwilightState()=" + mTwilight.getLastTwilightState());
         pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
         pw.println("  mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
         pw.println("  mAmbientLux=" + mAmbientLux);
@@ -522,19 +497,6 @@
             }
         }
 
-        if (mUseTwilight) {
-            TwilightState state = mTwilight.getLastTwilightState();
-            if (state != null && state.isNight()) {
-                final long duration = state.sunriseTimeMillis() - state.sunsetTimeMillis();
-                final long progress = System.currentTimeMillis() - state.sunsetTimeMillis();
-                final float amount = (float) Math.pow(2.0 * progress / duration - 1.0, 2.0);
-                gamma *= 1 + amount * TWILIGHT_ADJUSTMENT_MAX_GAMMA;
-                if (DEBUG) {
-                    Slog.d(TAG, "updateAutoBrightness: twilight amount=" + amount);
-                }
-            }
-        }
-
         if (gamma != 1.0f) {
             final float in = value;
             value = MathUtils.pow(value, gamma);
@@ -649,13 +611,6 @@
         }
     };
 
-    private final TwilightListener mTwilightListener = new TwilightListener() {
-        @Override
-        public void onTwilightStateChanged(@Nullable TwilightState state) {
-            updateAutoBrightness(true /*sendUpdate*/);
-        }
-    };
-
     /** Callbacks to request updates to the display's power state. */
     interface Callbacks {
         void updateBrightness();
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 015345c..bed269c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -642,7 +642,7 @@
                     && mPowerRequest.brightnessSetByUser;
             mAutomaticBrightnessController.configure(autoBrightnessEnabled,
                     mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
-                    userInitiatedChange, mPowerRequest.useTwilight);
+                    userInitiatedChange);
         }
 
         // Apply brightness boost.
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 7237fdb..cba694c 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -141,8 +141,7 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
-            IVrManager vrManager =
-                    (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
+            IVrManager vrManager = (IVrManager) getBinderService(Context.VR_SERVICE);
             if (vrManager != null) {
                 try {
                     vrManager.registerListener(mVrStateCallbacks);
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index d1f7cfd..e83b228 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -83,6 +83,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -113,6 +114,8 @@
             new ArrayList<>();
     private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
             new CopyOnWriteArrayList<>();
+    private final Map<Integer, Long> mAuthenticatorIds =
+            Collections.synchronizedMap(new HashMap<>());
     private final AppOpsManager mAppOps;
     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
     private static final int MAX_FAILED_ATTEMPTS = 5;
@@ -130,7 +133,6 @@
     private final UserManager mUserManager;
     private ClientMonitor mCurrentClient;
     private ClientMonitor mPendingClient;
-    private long mCurrentAuthenticatorId;
     private PerformanceStats mPerformanceStats;
 
     // Normal fingerprint authentications are tracked by mPerformanceMap.
@@ -239,6 +241,7 @@
 
             if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
             if (mHalDeviceId != 0) {
+                loadAuthenticatorIds();
                 updateActiveGroup(ActivityManager.getCurrentUser(), null);
             } else {
                 Slog.w(TAG, "Failed to open Fingerprint HAL!");
@@ -249,6 +252,26 @@
         return mDaemon;
     }
 
+    /** Populates existing authenticator ids. To be used only during the start of the service. */
+    private void loadAuthenticatorIds() {
+        // This operation can be expensive, so keep track of the elapsed time. Might need to move to
+        // background if it takes too long.
+        long t = System.currentTimeMillis();
+
+        mAuthenticatorIds.clear();
+        for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+            int userId = getUserOrWorkProfileId(null, user.id);
+            if (!mAuthenticatorIds.containsKey(userId)) {
+                updateActiveGroup(userId, null);
+            }
+        }
+
+        t = System.currentTimeMillis() - t;
+        if (t > 1000) {
+            Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
+        }
+    }
+
     protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
         if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid="
                 + groupId + "rem=" + remaining);
@@ -499,14 +522,23 @@
 
     boolean isCurrentUserOrProfile(int userId) {
         UserManager um = UserManager.get(mContext);
-
-        // Allow current user or profiles of the current user...
-        for (int profileId : um.getEnabledProfileIds(mCurrentUserId)) {
-            if (profileId == userId) {
-                return true;
-            }
+        if (um == null) {
+            Slog.e(TAG, "Unable to acquire UserManager");
+            return false;
         }
-        return false;
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            // Allow current user or profiles of the current user...
+            for (int profileId : um.getEnabledProfileIds(mCurrentUserId)) {
+                if (profileId == userId) {
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     private boolean isForegroundActivity(int uid, int pid) {
@@ -1195,7 +1227,7 @@
                     daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
                     mCurrentUserId = userId;
                 }
-                mCurrentAuthenticatorId = daemon.getAuthenticatorId();
+                mAuthenticatorIds.put(userId, daemon.getAuthenticatorId());
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to setActiveGroup():", e);
             }
@@ -1218,8 +1250,14 @@
      * @return true if this is a work profile
      */
     private boolean isWorkProfile(int userId) {
-        UserInfo info = mUserManager.getUserInfo(userId);
-        return info != null && info.isManagedProfile();
+        UserInfo userInfo = null;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            userInfo = mUserManager.getUserInfo(userId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return userInfo != null && userInfo.isManagedProfile();
     }
 
     private void listenForUserSwitches() {
@@ -1239,9 +1277,11 @@
 
     /***
      * @param opPackageName the name of the calling package
-     * @return authenticator id for the current user
+     * @return authenticator id for the calling user
      */
     public long getAuthenticatorId(String opPackageName) {
-        return mCurrentAuthenticatorId;
+        final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
+        Long authenticatorId = mAuthenticatorIds.get(userId);
+        return authenticatorId != null ? authenticatorId : 0;
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 4a10f50..07c3a38 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -25,7 +25,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Predicate;
 import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
@@ -34,6 +33,7 @@
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.function.Predicate;
 import java.util.concurrent.ArrayBlockingQueue;
 import libcore.util.EmptyArray;
 import sun.util.locale.LanguageTag;
@@ -77,7 +77,7 @@
     // Predicate for whether the given logical address is remote device's one or not.
     private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
         @Override
-        public boolean apply(Integer address) {
+        public boolean test(Integer address) {
             return !isAllocatedLocalDeviceAddress(address);
         }
     };
@@ -85,7 +85,7 @@
     // Predicate whether the given logical address is system audio's one or not
     private final Predicate<Integer> mSystemAudioAddressPredicate = new Predicate<Integer>() {
         @Override
-        public boolean apply(Integer address) {
+        public boolean test(Integer address) {
             return HdmiUtils.getTypeFromAddress(address) == Constants.ADDR_AUDIO_SYSTEM;
         }
     };
@@ -427,7 +427,7 @@
         switch (iterationStrategy) {
             case Constants.POLL_ITERATION_IN_ORDER:
                 for (int i = Constants.ADDR_TV; i <= Constants.ADDR_SPECIFIC_USE; ++i) {
-                    if (pickPredicate.apply(i)) {
+                    if (pickPredicate.test(i)) {
                         pollingCandidates.add(i);
                     }
                 }
@@ -435,7 +435,7 @@
             case Constants.POLL_ITERATION_REVERSE_ORDER:
             default:  // The default is reverse order.
                 for (int i = Constants.ADDR_SPECIFIC_USE; i >= Constants.ADDR_TV; --i) {
-                    if (pickPredicate.apply(i)) {
+                    if (pickPredicate.test(i)) {
                         pollingCandidates.add(i);
                     }
                 }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index b089ba7..7cb223d 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -70,6 +70,8 @@
             ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
     /** Amount of time a job is allowed to execute for before being considered timed-out. */
     private static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000;  // 10mins.
+    /** Amount of time the JobScheduler waits for the initial service launch+bind. */
+    private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000;
     /** Amount of time the JobScheduler will wait for a response from an app for a message. */
     private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
 
@@ -645,8 +647,20 @@
     private void scheduleOpTimeOut() {
         removeOpTimeOut();
 
-        final long timeoutMillis = (mVerb == VERB_EXECUTING) ?
-                EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
+        final long timeoutMillis;
+        switch (mVerb) {
+            case VERB_EXECUTING:
+                timeoutMillis = EXECUTING_TIMESLICE_MILLIS;
+                break;
+
+            case VERB_BINDING:
+                timeoutMillis = OP_BIND_TIMEOUT_MILLIS;
+                break;
+
+            default:
+                timeoutMillis = OP_TIMEOUT_MILLIS;
+                break;
+        }
         if (DEBUG) {
             Slog.d(TAG, "Scheduling time out for '" +
                     mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index eb8f8fc..17b005d 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -72,7 +72,6 @@
 import android.provider.Settings;
 import android.provider.Telephony.Carriers;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.SmsMessage;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
@@ -82,17 +81,17 @@
 import android.util.Log;
 import android.util.NtpTrustedTime;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.io.StringReader;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
+import java.util.List;
 import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Map;
@@ -411,7 +410,6 @@
     private WorkSource mClientSource = new WorkSource();
 
     private GeofenceHardwareImpl mGeofenceHardwareImpl;
-
     private int mYearOfHardware = 0;
 
     // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
@@ -1125,6 +1123,7 @@
 
             mGnssMeasurementsProvider.onGpsEnabledChanged();
             mGnssNavigationMessageProvider.onGpsEnabledChanged();
+            enableBatching();
         } else {
             synchronized (mLock) {
                 mEnabled = false;
@@ -1156,6 +1155,7 @@
         mAlarmManager.cancel(mWakeupIntent);
         mAlarmManager.cancel(mTimeoutIntent);
 
+        disableBatching();
         // do this before releasing wakelock
         native_cleanup();
 
@@ -1791,6 +1791,84 @@
         };
     }
 
+    public interface GnssBatchingProvider {
+        /**
+         * Returns the GNSS batching size
+         */
+        int getSize();
+        /**
+         * Starts the hardware batching operation
+         */
+        boolean start(long periodNanos, boolean wakeOnFifoFull);
+        /**
+         * Forces a flush of existing locations from the hardware batching
+         */
+        void flush();
+        /**
+         * Stops the batching operation
+         */
+        boolean stop();
+    }
+
+    /**
+     * @hide
+     */
+    public GnssBatchingProvider getGnssBatchingProvider() {
+        return new GnssBatchingProvider() {
+            @Override
+            public int getSize() {
+                return native_get_batch_size();
+            }
+            @Override
+            public boolean start(long periodNanos, boolean wakeOnFifoFull) {
+                if (periodNanos <= 0) {
+                    Log.e(TAG, "Invalid periodNanos " + periodNanos +
+                            "in batching request, not started");
+                    return false;
+                }
+                return native_start_batch(periodNanos, wakeOnFifoFull);
+            }
+            @Override
+            public void flush() {
+                native_flush_batch();
+            }
+            @Override
+            public boolean stop() {
+                return native_stop_batch();
+            }
+        };
+    }
+
+    /**
+     * Initialize Batching if enabled
+     */
+    private void enableBatching() {
+        if (!native_init_batching()) {
+            Log.e(TAG, "Failed to initialize GNSS batching");
+        };
+    }
+
+    /**
+     * Disable batching
+     */
+    private void disableBatching() {
+        native_stop_batch();
+        native_cleanup_batching();
+    }
+
+    /**
+     * called from native code - GNSS location batch callback
+     */
+    private void reportLocationBatch(Location[] locationArray) {
+        List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
+        if(DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + "reported"); }
+        try {
+            mILocationManager.reportLocationBatch(locations);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException calling reportLocationBatch");
+        }
+    }
+
     /**
      * called from native code to request XTRA data
      */
@@ -2117,7 +2195,10 @@
         // note that this assumes the message will not be removed from the queue before
         // it is handled (otherwise the wake lock would be leaked).
         mWakeLock.acquire();
-        Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
+        if (Log.isLoggable(TAG, Log.INFO)) {
+            Log.i(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg
+                    + ", " + obj + ")");
+        }
         mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
     }
 
@@ -2175,8 +2256,10 @@
             if (msg.arg2 == 1) {
                 // wakelock was taken for this message, release it
                 mWakeLock.release();
-                Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
-                        + msg.obj + ")");
+                if (Log.isLoggable(TAG, Log.INFO)) {
+                    Log.i(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message)
+                            + ", " + msg.arg1 + ", " + msg.obj + ")");
+                }
             }
         }
 
@@ -2424,6 +2507,40 @@
         }
     }
 
+    /**
+     * @return A string representing the given message ID.
+     */
+    private String messageIdAsString(int message) {
+        switch (message) {
+            case ENABLE:
+                return "ENABLE";
+            case SET_REQUEST:
+                return "SET_REQUEST";
+            case UPDATE_NETWORK_STATE:
+                return "UPDATE_NETWORK_STATE";
+            case REQUEST_SUPL_CONNECTION:
+                return "REQUEST_SUPL_CONNECTION";
+            case RELEASE_SUPL_CONNECTION:
+                return "RELEASE_SUPL_CONNECTION";
+            case INJECT_NTP_TIME:
+                return "INJECT_NTP_TIME";
+            case DOWNLOAD_XTRA_DATA:
+                return "DOWNLOAD_XTRA_DATA";
+            case INJECT_NTP_TIME_FINISHED:
+                return "INJECT_NTP_TIME_FINISHED";
+            case DOWNLOAD_XTRA_DATA_FINISHED:
+                return "DOWNLOAD_XTRA_DATA_FINISHED";
+            case UPDATE_LOCATION:
+                return "UPDATE_LOCATION";
+            case SUBSCRIPTION_OR_SIM_CHANGED:
+                return "SUBSCRIPTION_OR_SIM_CHANGED";
+            case INITIALIZE_HANDLER:
+                return "INITIALIZE_HANDLER";
+            default:
+                return "<Unknown>";
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         StringBuilder s = new StringBuilder();
@@ -2441,7 +2558,9 @@
         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
         s.append(")\n");
 
-        s.append(native_get_internal_state());
+        s.append("  internal state: ").append(native_get_internal_state());
+        s.append("\n");
+
         pw.append(s);
     }
 
@@ -2562,4 +2681,12 @@
     private static native boolean native_set_gps_lock(int gpsLock);
     private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
 
+    // GNSS Batching
+    private static native int native_get_batch_size();
+    private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
+    private static native void native_flush_batch();
+    private static native boolean native_stop_batch();
+    private static native boolean native_init_batching();
+    private static native void native_cleanup_batching();
+
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index ede6e30..10ecb86 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -1123,6 +1123,38 @@
             }
         }
 
+        public void addQueueItem(MediaDescription description) {
+            try {
+                mCb.onAddQueueItem(description);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in addQueueItem.", e);
+            }
+        }
+
+        public void addQueueItemAt(MediaDescription description, int index) {
+            try {
+                mCb.onAddQueueItemAt(description, index);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in addQueueItemAt.", e);
+            }
+        }
+
+        public void removeQueueItem(MediaDescription description) {
+            try {
+                mCb.onRemoveQueueItem(description);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in removeQueueItem.", e);
+            }
+        }
+
+        public void removeQueueItemAt(int index) {
+            try {
+                mCb.onRemoveQueueItemAt(index);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in removeQueueItem.", e);
+            }
+        }
+
         public void adjustVolume(int direction) {
             try {
                 mCb.onAdjustVolume(direction);
@@ -1397,6 +1429,30 @@
         }
 
         @Override
+        public void addQueueItem(MediaDescription description) {
+            updateCallingPackage();
+            mSessionCb.addQueueItem(description);
+        }
+
+        @Override
+        public void addQueueItemAt(MediaDescription description, int index) {
+            updateCallingPackage();
+            mSessionCb.addQueueItemAt(description, index);
+        }
+
+        @Override
+        public void removeQueueItem(MediaDescription description) {
+            updateCallingPackage();
+            mSessionCb.removeQueueItem(description);
+        }
+
+        @Override
+        public void removeQueueItemAt(int index) {
+            updateCallingPackage();
+            mSessionCb.removeQueueItemAt(index);
+        }
+
+        @Override
         public CharSequence getQueueTitle() {
             return mQueueTitle;
         }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 3bf95ef..98177fe 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -155,10 +155,10 @@
     }
 
     /**
-     * Tells the system UI that volume has changed on a remote session.
+     * Tells the system UI that volume has changed on an active remote session.
      */
     public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
-        if (mRvc == null) {
+        if (mRvc == null || !session.isActive()) {
             return;
         }
         try {
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 279bf90..d6c89a4 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -159,8 +159,7 @@
     }
 
     private boolean isMediaNotification(NotificationRecord record) {
-        return record.getNotification().extras.getParcelable(
-                Notification.EXTRA_MEDIA_SESSION) != null;
+        return record.getNotification().hasMediaSession();
     }
 
     private boolean isCall(NotificationRecord record) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b543b73..cc3fc00 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -115,6 +115,9 @@
 import android.service.notification.NotificationAssistantService;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationRankingUpdate;
+import android.service.notification.NotificationRecordProto;
+import android.service.notification.NotificationServiceDumpProto;
+import android.service.notification.NotificationServiceProto;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.ZenModeConfig;
@@ -128,6 +131,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
 import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -1694,7 +1698,7 @@
 
 
         @Override
-        public void clearData(String packageName, int uid) throws RemoteException {
+        public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
             checkCallerIsSystem();
 
             // Cancel posted notifications
@@ -1709,8 +1713,10 @@
             mConditionProviders.onPackagesChanged(true, new String[] {packageName});
 
             // Reset notification preferences
-            mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
-                    new String[] {packageName}, new int[] {uid});
+            if (!fromApp) {
+                mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
+                        new String[]{packageName}, new int[]{uid});
+            }
 
             savePolicyFile();
         }
@@ -2400,6 +2406,8 @@
             final DumpFilter filter = DumpFilter.parseFromArguments(args);
             if (filter != null && filter.stats) {
                 dumpJson(pw, filter);
+            } else if (filter != null && filter.proto) {
+                dumpProto(fd, filter);
             } else {
                 dumpImpl(pw, filter);
             }
@@ -2764,6 +2772,33 @@
         pw.println(dump);
     }
 
+    private void dumpProto(FileDescriptor fd, DumpFilter filter) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+        synchronized (mNotificationLock) {
+            long records = proto.start(NotificationServiceDumpProto.RECORDS);
+            int N = mNotificationList.size();
+            if (N > 0) {
+                for (int i = 0; i < N; i++) {
+                    final NotificationRecord nr = mNotificationList.get(i);
+                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
+                    nr.dump(proto, filter.redact);
+                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
+                }
+            }
+            N = mEnqueuedNotifications.size();
+            if (N > 0) {
+                for (int i = 0; i < N; i++) {
+                    final NotificationRecord nr = mEnqueuedNotifications.get(i);
+                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
+                    nr.dump(proto, filter.redact);
+                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
+                }
+            }
+            proto.end(records);
+        }
+        proto.flush();
+    }
+
     void dumpImpl(PrintWriter pw, DumpFilter filter) {
         pw.print("Current Notification Manager state");
         if (filter.filtered) {
@@ -4822,11 +4857,15 @@
         public long since;
         public boolean stats;
         public boolean redact = true;
+        public boolean proto = false;
 
         public static DumpFilter parseFromArguments(String[] args) {
             final DumpFilter filter = new DumpFilter();
             for (int ai = 0; ai < args.length; ai++) {
                 final String a = args[ai];
+                if ("--proto".equals(args[0])) {
+                    filter.proto = true;
+                }
                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
                     filter.redact = false;
                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index d26aa9e..3016b17 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -37,12 +37,14 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationRecordProto;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
@@ -185,7 +187,9 @@
         int defaultLightOff = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_defaultNotificationLedOff);
 
-        Light light = getChannel().shouldShowLights() ? new Light(defaultLightColor,
+        int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
+                : defaultLightColor;
+        Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
                 defaultLightOn, defaultLightOff) : null;
         if (mPreChannelsNotification
                 && (getChannel().getUserLockedFields()
@@ -335,6 +339,24 @@
     /** @deprecated Use {@link #getUser()} instead. */
     public int getUserId() { return sbn.getUserId(); }
 
+    void dump(ProtoOutputStream proto, boolean redact) {
+        proto.write(NotificationRecordProto.KEY, sbn.getKey());
+        if (getChannel() != null) {
+            proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
+        }
+        proto.write(NotificationRecordProto.CAN_SHOW_LIGHT, getLight() != null);
+        proto.write(NotificationRecordProto.CAN_VIBRATE, getVibration() != null);
+        proto.write(NotificationRecordProto.FLAGS, sbn.getNotification().flags);
+        proto.write(NotificationRecordProto.GROUP_KEY, getGroupKey());
+        proto.write(NotificationRecordProto.IMPORTANCE, getImportance());
+        if (getSound() != null) {
+            proto.write(NotificationRecordProto.SOUND, getSound().toString());
+        }
+        if (getAudioAttributes() != null) {
+            proto.write(NotificationRecordProto.SOUND_USAGE, getAudioAttributes().getUsage());
+        }
+    }
+
     void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
         final Notification notification = sbn.getNotification();
         final Icon icon = notification.getSmallIcon();
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 8176e5d..46c449b 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -563,7 +563,8 @@
             channel.setImportance(updatedChannel.getImportance());
         }
         if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
-            channel.setLights(updatedChannel.shouldShowLights());
+            channel.enableLights(updatedChannel.shouldShowLights());
+            channel.setLightColor(updatedChannel.getLightColor());
         }
         if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_PRIORITY) == 0) {
             channel.setBypassDnd(updatedChannel.canBypassDnd());
@@ -673,7 +674,7 @@
     public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
             int uid, boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
-        List<NotificationChannelGroup> groups = new ArrayList<>();
+        Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
         Record r = getRecord(pkg, uid);
         if (r == null) {
             return ParceledListSlice.emptyList();
@@ -684,23 +685,21 @@
             final NotificationChannel nc = r.channels.valueAt(i);
             if (includeDeleted || !nc.isDeleted()) {
                 if (nc.getGroup() != null) {
-                    // lazily populate channel list
-                    NotificationChannelGroup ncg = r.groups.get(nc.getGroup());
+                    NotificationChannelGroup ncg = groups.get(nc.getGroup());
+                    if (ncg == null ) {
+                        ncg = r.groups.get(nc.getGroup()).clone();
+                        groups.put(nc.getGroup(), ncg);
+                    }
                     ncg.addChannel(nc);
                 } else {
                     nonGrouped.addChannel(nc);
                 }
             }
         }
-        for (NotificationChannelGroup group : r.groups.values()) {
-            if (group.getChannels().size() > 0) {
-                groups.add(group);
-            }
-        }
         if (nonGrouped.getChannels().size() > 0) {
-            groups.add(nonGrouped);
+            groups.put(null, nonGrouped);
         }
-        return new ParceledListSlice<>(groups);
+        return new ParceledListSlice<>(new ArrayList<>(groups.values()));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 66977d6..7aa96cf 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -252,7 +252,7 @@
             return result;
         }
 
-        if (SystemProperties.getBoolean("dalvik.vm.deopt.secondary", false)) {
+        if (SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
             result = reconcileSecondaryDexFiles(pm.getDexManager());
             if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
                 return result;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0e5ea6e..4207998 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -833,7 +833,6 @@
     private List<String> mKeepUninstalledPackages;
 
     private UserManagerInternal mUserManagerInternal;
-    private final UserDataPreparer mUserDataPreparer;
 
     private File mCacheDir;
 
@@ -1937,7 +1936,7 @@
 
                     // Clean up any users or apps that were removed or recreated
                     // while this volume was missing
-                    reconcileUsers(volumeUuid);
+                    sUserManager.reconcileUsers(volumeUuid);
                     reconcileApps(volumeUuid);
 
                     // Clean up any install sessions that expired or were
@@ -2161,19 +2160,24 @@
         if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
             SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
             // We will wait for up to 100 seconds.
-            final long timeEnd = SystemClock.uptimeMillis() + 100 * 1000;
+            final long timeStart = SystemClock.uptimeMillis();
+            final long timeEnd = timeStart + 100 * 1000;
+            long timeNow = timeStart;
             while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
                 try {
                     Thread.sleep(WAIT_TIME_MS);
                 } catch (InterruptedException e) {
                     // Do nothing
                 }
-                if (SystemClock.uptimeMillis() > timeEnd) {
+                timeNow = SystemClock.uptimeMillis();
+                if (timeNow > timeEnd) {
                     SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
                     Slog.wtf(TAG, "cppreopt did not finish!");
                     break;
                 }
             }
+
+            Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms");
         }
     }
 
@@ -2265,8 +2269,8 @@
             mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
             mAsecInternalPath = new File(dataDir, "app-asec").getPath();
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
-            mUserDataPreparer = new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore);
-            sUserManager = new UserManagerService(context, this, mUserDataPreparer, mPackages);
+            sUserManager = new UserManagerService(context, this,
+                    new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
 
             // Propagate permission configuration in to package manager.
             ArrayMap<String, SystemConfig.PermissionEntry> permConfig
@@ -19966,7 +19970,7 @@
         });
 
         // Now that we're mostly running, clean up stale users and apps
-        reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
+        sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
         reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
     }
 
@@ -21304,60 +21308,6 @@
         }
     }
 
-    /**
-     * Examine all users present on given mounted volume, and destroy data
-     * belonging to users that are no longer valid, or whose user ID has been
-     * recycled.
-     */
-    private void reconcileUsers(String volumeUuid) {
-        final List<File> files = new ArrayList<>();
-        Collections.addAll(files, FileUtils
-                .listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
-        Collections.addAll(files, FileUtils
-                .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
-        Collections.addAll(files, FileUtils
-                .listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
-        Collections.addAll(files, FileUtils
-                .listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
-        Collections.addAll(files, FileUtils
-                .listFilesOrEmpty(Environment.getDataMiscCeDirectory()));
-        for (File file : files) {
-            if (!file.isDirectory()) continue;
-
-            final int userId;
-            final UserInfo info;
-            try {
-                userId = Integer.parseInt(file.getName());
-                info = sUserManager.getUserInfo(userId);
-            } catch (NumberFormatException e) {
-                Slog.w(TAG, "Invalid user directory " + file);
-                continue;
-            }
-
-            boolean destroyUser = false;
-            if (info == null) {
-                logCriticalInfo(Log.WARN, "Destroying user directory " + file
-                        + " because no matching user was found");
-                destroyUser = true;
-            } else if (!mOnlyCore) {
-                try {
-                    UserManagerService.enforceSerialNumber(file, info.serialNumber);
-                } catch (IOException e) {
-                    logCriticalInfo(Log.WARN, "Destroying user directory " + file
-                            + " because we failed to enforce serial number: " + e);
-                    destroyUser = true;
-                }
-            }
-
-            if (destroyUser) {
-                synchronized (mInstallLock) {
-                    mUserDataPreparer.destroyUserDataLI(volumeUuid, userId,
-                            StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
-                }
-            }
-        }
-    }
-
     private void assertPackageKnown(String volumeUuid, String packageName)
             throws PackageManagerException {
         synchronized (mPackages) {
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 52599fd..fc00acc 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -17,13 +17,28 @@
 package com.android.server.pm;
 
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 import static com.android.server.pm.PackageManagerService.logCriticalInfo;
 
@@ -31,6 +46,9 @@
  * Helper class for preparing and destroying user storage
  */
 class UserDataPreparer {
+    private static final String TAG = "UserDataPreparer";
+    private static final String XATTR_SERIAL = "user.serial";
+
     private final Object mInstallLock;
     private final Context mContext;
     private final boolean mOnlyCore;
@@ -65,19 +83,15 @@
             storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
 
             if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
-                UserManagerService.enforceSerialNumber(
-                        Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial);
+                enforceSerialNumber(getDataUserDeDirectory(volumeUuid, userId), userSerial);
                 if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
-                    UserManagerService.enforceSerialNumber(
-                            Environment.getDataSystemDeDirectory(userId), userSerial);
+                    enforceSerialNumber(getDataSystemDeDirectory(userId), userSerial);
                 }
             }
             if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
-                UserManagerService.enforceSerialNumber(
-                        Environment.getDataUserCeDirectory(volumeUuid, userId), userSerial);
+                enforceSerialNumber(getDataUserCeDirectory(volumeUuid, userId), userSerial);
                 if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
-                    UserManagerService.enforceSerialNumber(
-                            Environment.getDataSystemCeDirectory(userId), userSerial);
+                    enforceSerialNumber(getDataSystemCeDirectory(userId), userSerial);
                 }
             }
 
@@ -117,13 +131,13 @@
             // Clean up system data
             if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
                 if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
-                    FileUtils.deleteContentsAndDir(Environment.getUserSystemDirectory(userId));
-                    FileUtils.deleteContentsAndDir(Environment.getDataSystemDeDirectory(userId));
-                    FileUtils.deleteContentsAndDir(Environment.getDataMiscDeDirectory(userId));
+                    FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId));
+                    FileUtils.deleteContentsAndDir(getDataSystemDeDirectory(userId));
+                    FileUtils.deleteContentsAndDir(getDataMiscDeDirectory(userId));
                 }
                 if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
-                    FileUtils.deleteContentsAndDir(Environment.getDataSystemCeDirectory(userId));
-                    FileUtils.deleteContentsAndDir(Environment.getDataMiscCeDirectory(userId));
+                    FileUtils.deleteContentsAndDir(getDataSystemCeDirectory(userId));
+                    FileUtils.deleteContentsAndDir(getDataMiscCeDirectory(userId));
                 }
             }
 
@@ -136,4 +150,183 @@
         }
     }
 
+    /**
+     * Examine all users present on given mounted volume, and destroy data
+     * belonging to users that are no longer valid, or whose user ID has been
+     * recycled.
+     */
+    void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList) {
+        final List<File> files = new ArrayList<>();
+        Collections.addAll(files, FileUtils
+                .listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
+        Collections.addAll(files, FileUtils
+                .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
+        Collections.addAll(files, FileUtils
+                .listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
+        Collections.addAll(files, FileUtils
+                .listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
+        Collections.addAll(files, FileUtils
+                .listFilesOrEmpty(Environment.getDataMiscCeDirectory()));
+        reconcileUsers(volumeUuid, validUsersList, files);
+    }
+
+    @VisibleForTesting
+    void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList, List<File> files) {
+        final int userCount = validUsersList.size();
+        SparseArray<UserInfo> users = new SparseArray<>(userCount);
+        for (int i = 0; i < userCount; i++) {
+            UserInfo user = validUsersList.get(i);
+            users.put(user.id, user);
+        }
+        for (File file : files) {
+            if (!file.isDirectory()) {
+                continue;
+            }
+
+            final int userId;
+            final UserInfo info;
+            try {
+                userId = Integer.parseInt(file.getName());
+                info = users.get(userId);
+            } catch (NumberFormatException e) {
+                Slog.w(TAG, "Invalid user directory " + file);
+                continue;
+            }
+
+            boolean destroyUser = false;
+            if (info == null) {
+                logCriticalInfo(Log.WARN, "Destroying user directory " + file
+                        + " because no matching user was found");
+                destroyUser = true;
+            } else if (!mOnlyCore) {
+                try {
+                    enforceSerialNumber(file, info.serialNumber);
+                } catch (IOException e) {
+                    logCriticalInfo(Log.WARN, "Destroying user directory " + file
+                            + " because we failed to enforce serial number: " + e);
+                    destroyUser = true;
+                }
+            }
+
+            if (destroyUser) {
+                synchronized (mInstallLock) {
+                    destroyUserDataLI(volumeUuid, userId,
+                            StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+                }
+            }
+        }
+    }
+
+    @VisibleForTesting
+    protected File getDataMiscCeDirectory(int userId) {
+        return Environment.getDataMiscCeDirectory(userId);
+    }
+
+    @VisibleForTesting
+    protected File getDataSystemCeDirectory(int userId) {
+        return Environment.getDataSystemCeDirectory(userId);
+    }
+
+    @VisibleForTesting
+    protected File getDataMiscDeDirectory(int userId) {
+        return Environment.getDataMiscDeDirectory(userId);
+    }
+
+    @VisibleForTesting
+    protected File getUserSystemDirectory(int userId) {
+        return Environment.getUserSystemDirectory(userId);
+    }
+
+    @VisibleForTesting
+    protected File getDataUserCeDirectory(String volumeUuid, int userId) {
+        return Environment.getDataUserCeDirectory(volumeUuid, userId);
+    }
+
+    @VisibleForTesting
+    protected File getDataSystemDeDirectory(int userId) {
+        return Environment.getDataSystemDeDirectory(userId);
+    }
+
+    @VisibleForTesting
+    protected File getDataUserDeDirectory(String volumeUuid, int userId) {
+        return Environment.getDataUserDeDirectory(volumeUuid, userId);
+    }
+
+    @VisibleForTesting
+    protected boolean isFileEncryptedEmulatedOnly() {
+        return StorageManager.isFileEncryptedEmulatedOnly();
+    }
+
+    /**
+     * Enforce that serial number stored in user directory inode matches the
+     * given expected value. Gracefully sets the serial number if currently
+     * undefined.
+     *
+     * @throws IOException when problem extracting serial number, or serial
+     *             number is mismatched.
+     */
+    void enforceSerialNumber(File file, int serialNumber) throws IOException {
+        if (isFileEncryptedEmulatedOnly()) {
+            // When we're emulating FBE, the directory may have been chmod
+            // 000'ed, meaning we can't read the serial number to enforce it;
+            // instead of destroying the user, just log a warning.
+            Slog.w(TAG, "Device is emulating FBE; assuming current serial number is valid");
+            return;
+        }
+
+        final int foundSerial = getSerialNumber(file);
+        Slog.v(TAG, "Found " + file + " with serial number " + foundSerial);
+
+        if (foundSerial == -1) {
+            Slog.d(TAG, "Serial number missing on " + file + "; assuming current is valid");
+            try {
+                setSerialNumber(file, serialNumber);
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to set serial number on " + file, e);
+            }
+
+        } else if (foundSerial != serialNumber) {
+            throw new IOException("Found serial number " + foundSerial
+                    + " doesn't match expected " + serialNumber);
+        }
+    }
+
+    /**
+     * Set serial number stored in user directory inode.
+     *
+     * @throws IOException if serial number was already set
+     */
+    private static void setSerialNumber(File file, int serialNumber) throws IOException {
+        try {
+            final byte[] buf = Integer.toString(serialNumber).getBytes(StandardCharsets.UTF_8);
+            Os.setxattr(file.getAbsolutePath(), XATTR_SERIAL, buf, OsConstants.XATTR_CREATE);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
+
+    /**
+     * Return serial number stored in user directory inode.
+     *
+     * @return parsed serial number, or -1 if not set
+     */
+    @VisibleForTesting
+    static int getSerialNumber(File file) throws IOException {
+        try {
+            final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL);
+            final String serial = new String(buf);
+            try {
+                return Integer.parseInt(serial);
+            } catch (NumberFormatException e) {
+                throw new IOException("Bad serial number: " + serial);
+            }
+        } catch (ErrnoException e) {
+            if (e.errno == OsConstants.ENODATA) {
+                return -1;
+            } else {
+                throw e.rethrowAsIOException();
+            }
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 455d3e4..627fa54 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -218,8 +218,6 @@
     static final int WRITE_USER_MSG = 1;
     static final int WRITE_USER_DELAY = 2*1000;  // 2 seconds
 
-    private static final String XATTR_SERIAL = "user.serial";
-
     // Tron counters
     private static final String TRON_GUEST_CREATED = "users_guest_created";
     private static final String TRON_USER_CREATED = "users_user_created";
@@ -3159,6 +3157,15 @@
     }
 
     /**
+     * Examine all users present on given mounted volume, and destroy data
+     * belonging to users that are no longer valid, or whose user ID has been
+     * recycled.
+     */
+    void reconcileUsers(String volumeUuid) {
+        mUserDataPreparer.reconcileUsers(volumeUuid, getUsers(true /* excludeDying */));
+    }
+
+    /**
      * Make a note of the last started time of a user and do some cleanup.
      * This is called with ActivityManagerService lock held.
      * @param userId the user that was just foregrounded
@@ -3219,78 +3226,6 @@
         return RESTRICTIONS_FILE_PREFIX + packageName + XML_SUFFIX;
     }
 
-    /**
-     * Enforce that serial number stored in user directory inode matches the
-     * given expected value. Gracefully sets the serial number if currently
-     * undefined.
-     *
-     * @throws IOException when problem extracting serial number, or serial
-     *             number is mismatched.
-     */
-    public static void enforceSerialNumber(File file, int serialNumber) throws IOException {
-        if (StorageManager.isFileEncryptedEmulatedOnly()) {
-            // When we're emulating FBE, the directory may have been chmod
-            // 000'ed, meaning we can't read the serial number to enforce it;
-            // instead of destroying the user, just log a warning.
-            Slog.w(LOG_TAG, "Device is emulating FBE; assuming current serial number is valid");
-            return;
-        }
-
-        final int foundSerial = getSerialNumber(file);
-        Slog.v(LOG_TAG, "Found " + file + " with serial number " + foundSerial);
-
-        if (foundSerial == -1) {
-            Slog.d(LOG_TAG, "Serial number missing on " + file + "; assuming current is valid");
-            try {
-                setSerialNumber(file, serialNumber);
-            } catch (IOException e) {
-                Slog.w(LOG_TAG, "Failed to set serial number on " + file, e);
-            }
-
-        } else if (foundSerial != serialNumber) {
-            throw new IOException("Found serial number " + foundSerial
-                    + " doesn't match expected " + serialNumber);
-        }
-    }
-
-    /**
-     * Set serial number stored in user directory inode.
-     *
-     * @throws IOException if serial number was already set
-     */
-    private static void setSerialNumber(File file, int serialNumber)
-            throws IOException {
-        try {
-            final byte[] buf = Integer.toString(serialNumber).getBytes(StandardCharsets.UTF_8);
-            Os.setxattr(file.getAbsolutePath(), XATTR_SERIAL, buf, OsConstants.XATTR_CREATE);
-        } catch (ErrnoException e) {
-            throw e.rethrowAsIOException();
-        }
-    }
-
-    /**
-     * Return serial number stored in user directory inode.
-     *
-     * @return parsed serial number, or -1 if not set
-     */
-    private static int getSerialNumber(File file) throws IOException {
-        try {
-            final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL);
-            final String serial = new String(buf);
-            try {
-                return Integer.parseInt(serial);
-            } catch (NumberFormatException e) {
-                throw new IOException("Bad serial number: " + serial);
-            }
-        } catch (ErrnoException e) {
-            if (e.errno == OsConstants.ENODATA) {
-                return -1;
-            } else {
-                throw e.rethrowAsIOException();
-            }
-        }
-    }
-
     @Override
     public void setSeedAccountData(int userId, String accountName, String accountType,
             PersistableBundle accountOptions, boolean persist) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index d301463..0a1574b 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -474,11 +474,12 @@
                     }
                     break;
                 case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES:
-                    if (newValue) {
-                        android.provider.Settings.Secure.putIntForUser(cr,
-                                android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
-                                userId);
-                    }
+                    // Since Android O, the secure setting is not available to be changed by the
+                    // user. Hence, when the restriction is cleared, we need to reset the state of
+                    // the setting to its default value which is now 1.
+                    android.provider.Settings.Secure.putIntForUser(cr,
+                            android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
+                            newValue ? 0 : 1, userId);
                     break;
                 case UserManager.DISALLOW_RUN_IN_BACKGROUND:
                     if (newValue) {
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index 6edb4d2..7a28081 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -18,6 +18,7 @@
 
 import android.app.StatusBarManager;
 import android.os.Handler;
+import android.os.Message;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.View;
@@ -43,6 +44,8 @@
 
     private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
 
+    private static final int MSG_NAV_BAR_VISIBILITY_CHANGED = 1;
+
     protected final String mTag;
     private final int mTransientFlag;
     private final int mUnhideFlag;
@@ -63,6 +66,8 @@
     private boolean mSetUnHideFlagWhenNextTransparent;
     private boolean mNoAnimationOnNextShow;
 
+    private OnBarVisibilityChangedListener mVisibilityChangeListener;
+
     public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag,
             int statusBarManagerId, int translucentWmFlag, int transparentFlag) {
         mTag = "BarController." + tag;
@@ -72,7 +77,7 @@
         mStatusBarManagerId = statusBarManagerId;
         mTranslucentWmFlag = translucentWmFlag;
         mTransparentFlag = transparentFlag;
-        mHandler = new Handler();
+        mHandler = new BarHandler();
     }
 
     public void setWindow(WindowState win) {
@@ -153,9 +158,18 @@
         mNoAnimationOnNextShow = false;
         final int state = computeStateLw(wasVis, wasAnim, mWin, change);
         final boolean stateChanged = updateStateLw(state);
+
+        if (change && (mVisibilityChangeListener != null)) {
+            mHandler.obtainMessage(MSG_NAV_BAR_VISIBILITY_CHANGED, show ? 1 : 0, 0).sendToTarget();
+        }
+
         return change || stateChanged;
     }
 
+    void setOnBarVisibilityChangedListener(OnBarVisibilityChangedListener listener) {
+        mVisibilityChangeListener = listener;
+    }
+
     protected boolean skipAnimation() {
         return false;
     }
@@ -300,4 +314,22 @@
             pw.println(transientBarStateToString(mTransientBarState));
         }
     }
+
+    private class BarHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_NAV_BAR_VISIBILITY_CHANGED:
+                    final boolean visible = msg.arg1 != 0;
+                    if (mVisibilityChangeListener != null) {
+                        mVisibilityChangeListener.onBarVisibilityChanged(visible);
+                    }
+                    break;
+            }
+        }
+    }
+
+    interface OnBarVisibilityChangedListener {
+        void onBarVisibilityChanged(boolean visible);
+    }
 }
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 9bf0476..364bf28 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -125,7 +125,7 @@
 
     void systemReady() {
         IVrManager vrManager = IVrManager.Stub.asInterface(
-                ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
+                ServiceManager.getService(Context.VR_SERVICE));
         if (vrManager != null) {
             try {
                 vrManager.registerListener(mVrStateCallbacks);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 180f6c9..3e05157 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -149,6 +149,7 @@
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
+import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
 import android.hardware.power.V1_0.PowerHint;
 import android.media.AudioAttributes;
@@ -203,6 +204,7 @@
 import android.view.KeyCharacterMap.FallbackAction;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -990,6 +992,14 @@
             WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
             View.NAVIGATION_BAR_TRANSPARENT);
 
+    private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
+            new BarController.OnBarVisibilityChangedListener() {
+        @Override
+        public void onBarVisibilityChanged(boolean visible) {
+            mAccessibilityManager.notifyAccessibilityButtonAvailabilityChanged(visible);
+        }
+    };
+
     private ImmersiveModeConfirmation mImmersiveModeConfirmation;
 
     private SystemGesturesPointerEventListener mSystemGestures;
@@ -2900,6 +2910,8 @@
                 }
                 mNavigationBar = win;
                 mNavigationBarController.setWindow(win);
+                mNavigationBarController.setOnBarVisibilityChangedListener(
+                        mNavBarVisibilityListener);
                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
             case TYPE_NAVIGATION_BAR_PANEL:
@@ -4236,6 +4248,9 @@
                 mInputConsumer = mWindowManagerFuncs.createInputConsumer(mHandler.getLooper(),
                         INPUT_CONSUMER_NAVIGATION,
                         (channel, looper) -> new HideNavInputEventReceiver(channel, looper));
+                // As long as mInputConsumer is active, hover events are not dispatched to the app
+                // and the pointer icon is likely to become stale. Hide it to avoid confusion.
+                InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
             }
 
             // For purposes of positioning and showing the nav bar, if we have
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 238866a..ffbb428 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -517,9 +517,6 @@
     private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
             = new ArrayList<PowerManagerInternal.LowPowerModeListener>();
 
-    // True if brightness should be affected by twilight.
-    private boolean mBrightnessUseTwilight;
-
     // True if we are currently in VR Mode.
     private boolean mIsVrModeEnabled;
 
@@ -735,11 +732,7 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.DOUBLE_TAP_TO_WAKE),
                     false, mSettingsObserver, UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Secure.BRIGHTNESS_USE_TWILIGHT),
-                    false, mSettingsObserver, UserHandle.USER_ALL);
-            IVrManager vrManager =
-                    (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
+            IVrManager vrManager = (IVrManager) getBinderService(Context.VR_SERVICE);
             if (vrManager != null) {
                 try {
                     vrManager.registerListener(mVrStateCallbacks);
@@ -878,9 +871,6 @@
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
                 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
 
-        mBrightnessUseTwilight = Settings.Secure.getIntForUser(resolver,
-                Secure.BRIGHTNESS_USE_TWILIGHT, 0, UserHandle.USER_CURRENT) != 0;
-
         final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE, 0) != 0;
         final boolean autoLowPowerModeConfigured = Settings.Global.getInt(resolver,
@@ -2254,7 +2244,6 @@
             mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
             mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
             mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
-            mDisplayPowerRequest.useTwilight = mBrightnessUseTwilight;
 
             if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                 mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index fb0dd2a..b4467af 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -23,9 +23,6 @@
 
 public interface StatusBarManagerInternal {
     void setNotificationDelegate(NotificationDelegate delegate);
-    void buzzBeepBlinked();
-    void notificationLightPulse(int argb, int onMillis, int offMillis);
-    void notificationLightOff();
     void showScreenPinningRequest(int taskId);
     void showAssistDisclosure();
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 7b7db0e..2dfe20a8 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -120,40 +120,6 @@
         }
 
         @Override
-        public void buzzBeepBlinked() {
-            if (mBar != null) {
-                try {
-                    mBar.buzzBeepBlinked();
-                } catch (RemoteException ex) {
-                }
-            }
-        }
-
-        @Override
-        public void notificationLightPulse(int argb, int onMillis, int offMillis) {
-            mNotificationLightOn = true;
-            if (mBar != null) {
-                try {
-                    mBar.notificationLightPulse(argb, onMillis, offMillis);
-                } catch (RemoteException ex) {
-                }
-            }
-        }
-
-        @Override
-        public void notificationLightOff() {
-            if (mNotificationLightOn) {
-                mNotificationLightOn = false;
-                if (mBar != null) {
-                    try {
-                        mBar.notificationLightOff();
-                    } catch (RemoteException ex) {
-                    }
-                }
-            }
-        }
-
-        @Override
         public void showScreenPinningRequest(int taskId) {
             if (mBar != null) {
                 try {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 8cc53f0..e026130 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -23,15 +23,12 @@
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.OperationApplicationException;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -84,12 +81,9 @@
 import com.android.server.IoThread;
 import com.android.server.SystemService;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -241,44 +235,6 @@
                 // the update can be handled in {@link #onSomePackagesChanged}.
                 return true;
             }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                    if (!userState.packageSet.contains(packageName)) {
-                        // Not a TV input package.
-                        return;
-                    }
-                }
-
-                ArrayList<ContentProviderOperation> operations = new ArrayList<>();
-
-                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
-                String[] selectionArgs = { packageName };
-
-                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
-                        .withSelection(selection, selectionArgs).build());
-                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
-                        .withSelection(selection, selectionArgs).build());
-                operations.add(ContentProviderOperation
-                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
-                        .withSelection(selection, selectionArgs).build());
-
-                ContentProviderResult[] results = null;
-                try {
-                    ContentResolver cr = getContentResolverForUser(getChangingUserId());
-                    results = cr.applyBatch(TvContract.AUTHORITY, operations);
-                } catch (RemoteException | OperationApplicationException e) {
-                    Slog.e(TAG, "error in applyBatch", e);
-                }
-
-                if (DEBUG) {
-                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
-                            + ")");
-                    Slog.d(TAG, "results=" + results);
-                }
-            }
         };
         monitor.register(mContext, null, UserHandle.ALL, true);
 
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 0fc1900..45b7baf 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -79,4 +79,13 @@
      *       given in {@link android.service.vr.VrModeException} on failure.
      */
     public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
+
+    /**
+     * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
+     * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
+     * by VR viewers to indicate that a device is placed in a VR viewer.
+     *
+     * @param enabled true if the device should be placed in persistent VR mode.
+     */
+    public abstract void setPersistentVrModeEnabled(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index e8385fc..69a9f80 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -20,18 +20,12 @@
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
 import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.hardware.display.DisplayManager;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -54,7 +48,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
-import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.utils.ManagedApplicationService.PendingEvent;
@@ -70,8 +63,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
-import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -98,8 +89,6 @@
 
     public static final String TAG = "VrManagerService";
 
-    public static final String VR_MANAGER_BINDER_SERVICE = "vrmanager";
-
     private static final int PENDING_STATE_DELAY_MS = 300;
     private static final int EVENT_LOG_SIZE = 32;
     private static final int INVALID_APPOPS_MODE = -1;
@@ -122,8 +111,10 @@
     // State protected by mLock
     private boolean mVrModeAllowed;
     private boolean mVrModeEnabled;
+    private boolean mPersistentVrModeEnabled;
     private EnabledComponentsObserver mComponentObserver;
     private ManagedApplicationService mCurrentVrService;
+    private ComponentName mDefaultVrService;
     private Context mContext;
     private ComponentName mCurrentVrModeComponent;
     private int mCurrentVrModeUser;
@@ -138,7 +129,6 @@
     private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
     /** Tracks the state of the screen and keyguard UI.*/
     private int mSystemSleepFlags = FLAG_NONE;
-    private CompatibilityDisplay mCompatibilityDisplay;
 
     private static final int MSG_VR_STATE_CHANGE = 0;
     private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
@@ -159,6 +149,10 @@
             if (mVrModeAllowed) {
                 consumeAndApplyPendingStateLocked();
             } else {
+                // Disable persistent mode when VR mode isn't allowed, allows an escape hatch to
+                // exit persistent VR mode when screen is turned off.
+                mPersistentVrModeEnabled = false;
+
                 // Set pending state to current state.
                 mPendingState = (mVrModeEnabled && mCurrentVrService != null)
                     ? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(),
@@ -380,6 +374,12 @@
         }
 
         @Override
+        public void setPersistentVrModeEnabled(boolean enabled) {
+            enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS);
+            VrManagerService.this.setPersistentVrModeEnabled(enabled);
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -389,6 +389,8 @@
             }
             pw.println("********* Dump of VrManagerService *********");
             pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
+            pw.println("Persistent VR mode is currently: " +
+                    ((mPersistentVrModeEnabled) ? "enabled" : "disabled"));
             pw.println("Previous state transitions:\n");
             String tab = "  ";
             dumpStateTransitions(pw);
@@ -464,6 +466,11 @@
         public int hasVrPackage(ComponentName packageName, int userId) {
             return VrManagerService.this.hasVrPackage(packageName, userId);
         }
+
+        @Override
+        public void setPersistentVrModeEnabled(boolean enabled) {
+            VrManagerService.this.setPersistentVrModeEnabled(enabled);
+        }
     }
 
     public VrManagerService(Context context) {
@@ -478,7 +485,7 @@
         }
 
         publishLocalService(VrManagerInternal.class, new LocalService());
-        publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder());
+        publishBinderService(Context.VR_SERVICE, mVrManager.asBinder());
     }
 
     @Override
@@ -497,10 +504,14 @@
                 mComponentObserver.rebuildAll();
             }
 
-            DisplayManager dm =
-                    (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
-            mCompatibilityDisplay = new CompatibilityDisplay(dm, mVrManager);
-            mCompatibilityDisplay.init();
+            //TODO: something more robust than picking the first one
+            ArraySet<ComponentName> defaultVrComponents =
+                    SystemConfig.getInstance().getDefaultVrComponents();
+            if (defaultVrComponents.size() > 0) {
+                mDefaultVrService = defaultVrComponents.valueAt(0);
+            } else {
+                Slog.i(TAG, "No default vr listener service found.");
+            }
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             synchronized (mLock) {
                 mVrModeAllowed = true;
@@ -644,8 +655,8 @@
                 }
             }
 
+            mCurrentVrModeComponent = calling;
             if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
-                mCurrentVrModeComponent = calling;
                 sendUpdatedCaller = true;
             }
 
@@ -954,7 +965,25 @@
             int userId, @NonNull ComponentName callingPackage) {
 
         synchronized (mLock) {
-            VrState pending = new VrState(enabled, targetPackageName, userId, callingPackage);
+            VrState pending;
+            ComponentName targetListener;
+            ComponentName foregroundVrComponent;
+
+            // If the device is in persistent VR mode, then calls to disable VR mode are ignored,
+            // and the system default VR listener is used.
+            boolean targetEnabledState = enabled || mPersistentVrModeEnabled;
+            if (!enabled && mPersistentVrModeEnabled) {
+                targetListener = mDefaultVrService;
+
+                // Current foreground component isn't a VR one (in 2D app case)
+                foregroundVrComponent = null;
+            } else {
+                targetListener = targetPackageName;
+                foregroundVrComponent = callingPackage;
+            }
+            pending = new VrState(
+                    targetEnabledState, targetListener, userId, foregroundVrComponent);
+
             if (!mVrModeAllowed) {
                 // We're not allowed to be in VR mode.  Make this state pending.  This will be
                 // applied the next time we are allowed to enter VR mode unless it is superseded by
@@ -963,7 +992,7 @@
                 return;
             }
 
-            if (!enabled && mCurrentVrService != null) {
+            if (!targetEnabledState && mCurrentVrService != null) {
                 // If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
                 // and service bind/unbind in case we are immediately switching to another VR app.
                 if (mPendingState == null) {
@@ -978,7 +1007,19 @@
                 mPendingState = null;
             }
 
-            updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
+            updateCurrentVrServiceLocked(
+                    targetEnabledState, targetListener, userId, foregroundVrComponent);
+        }
+    }
+
+    private void setPersistentVrModeEnabled(boolean enabled) {
+        synchronized (mLock) {
+            mPersistentVrModeEnabled = enabled;
+
+            // Disabling persistent mode when not showing a VR should disable the overall vr mode.
+            if (!enabled && mCurrentVrModeComponent == null) {
+                setVrMode(false, null, 0, null);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 061aa83..2263042 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -173,10 +173,9 @@
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
             int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
             AppWindowContainerController controller) {
-        this(service, token, voiceInteraction, dc);
+        this(service, token, voiceInteraction, dc, fullscreen);
         setController(controller);
         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-        mFillsParent = fullscreen;
         mShowForAllUsers = showForAllUsers;
         mTargetSdk = targetSdk;
         mOrientation = orientation;
@@ -191,11 +190,12 @@
     }
 
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
-            DisplayContent dc) {
+            DisplayContent dc, boolean fillsParent) {
         super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
                 false /* ownerCanManageAppTokens */);
         appToken = token;
         mVoiceInteraction = voiceInteraction;
+        mFillsParent = fillsParent;
         mInputApplicationHandle = new InputApplicationHandle(this);
         mAppAnimator = new AppWindowAnimator(this, service);
     }
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 5a2ee9a..0a92a81 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -621,11 +621,7 @@
         final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
         final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisible())
                 || (homeStack.hasMultipleTaskWithHomeTaskNotTop());
-        // If the home task is an on-top launcher, we don't want to minimize the docked stack.
-        // Instead we want everything underneath that was visible to remain visible.
-        // See android.R.attr#onTopLauncher.
-        final boolean isOnTopLauncher = homeStack.topTaskIsOnTopLauncher();
-        setMinimizedDockedStack(homeVisible && !homeBehind && !isOnTopLauncher, animate);
+        setMinimizedDockedStack(homeVisible && !homeBehind, animate);
     }
 
     private boolean isWithinDisplay(Task task) {
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 596c3d8..a872ea4 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -22,7 +22,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-import android.animation.ValueAnimator;
 import android.app.RemoteAction;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
@@ -42,7 +41,6 @@
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
 
-import com.android.internal.policy.PipMotionHelper;
 import com.android.internal.policy.PipSnapAlgorithm;
 import com.android.server.UiThread;
 
@@ -51,7 +49,20 @@
 import java.util.List;
 
 /**
- * Holds the common state of the pinned stack between the system and SystemUI.
+ * Holds the common state of the pinned stack between the system and SystemUI. If SystemUI ever
+ * needs to be restarted, it will be notified with the last known state.
+ *
+ * Changes to the pinned stack also flow through this controller, and generally, the system only
+ * changes the pinned stack bounds through this controller in two ways:
+ *
+ * 1) When first entering PiP: the controller returns the valid bounds given, taking aspect ratio
+ *    and IME state into account.
+ * 2) When rotating the device: the controller calculates the new bounds in the new orientation,
+ *    taking the minimized and IME state into account. In this case, we currently ignore the
+ *    SystemUI adjustments (ie. expanded for menu, interaction, etc).
+ *
+ * Other changes in the system, including adjustment of IME, configuration change, and more are
+ * handled by SystemUI (similar to the docked stack divider).
  */
 class PinnedStackController {
 
@@ -67,18 +78,15 @@
 
     private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
     private final PipSnapAlgorithm mSnapAlgorithm;
-    private final PipMotionHelper mMotionHelper;
 
     // States that affect how the PIP can be manipulated
-    private boolean mInInteractiveMode;
     private boolean mIsMinimized;
-    private boolean mIsSnappingToEdge;
     private boolean mIsImeShowing;
     private int mImeHeight;
-    private ValueAnimator mBoundsAnimator = null;
 
-    // The set of actions that are currently allowed on the PiP activity
+    // The set of actions and aspect-ratio for the that are currently allowed on the PiP activity
     private ArrayList<RemoteAction> mActions = new ArrayList<>();
+    private float mAspectRatio = -1f;
 
     // Used to calculate stack bounds across rotations
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -89,6 +97,10 @@
     private Size mDefaultStackSize;
     private Point mScreenEdgeInsets;
 
+    // The aspect ratio bounds of the PIP.
+    private float mMinAspectRatio;
+    private float mMaxAspectRatio;
+
     // Temp vars for calculation
     private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
     private final Rect mTmpInsets = new Rect();
@@ -100,31 +112,12 @@
     private class PinnedStackControllerCallback extends IPinnedStackController.Stub {
 
         @Override
-        public void setInInteractiveMode(final boolean inInteractiveMode) {
-            mHandler.post(() -> {
-                // Cancel any existing animations on the PIP once the user starts dragging it
-                if (mBoundsAnimator != null && inInteractiveMode) {
-                    mBoundsAnimator.cancel();
-                }
-                mInInteractiveMode = inInteractiveMode;
-            });
-        }
-
-        @Override
         public void setIsMinimized(final boolean isMinimized) {
             mHandler.post(() -> {
                 mIsMinimized = isMinimized;
                 mSnapAlgorithm.setMinimized(isMinimized);
             });
         }
-
-        @Override
-        public void setSnapToEdge(final boolean snapToEdge) {
-            mHandler.post(() -> {
-                mIsSnappingToEdge = snapToEdge;
-                mSnapAlgorithm.setSnapToEdge(snapToEdge);
-            });
-        }
     }
 
     /**
@@ -135,7 +128,6 @@
         @Override
         public void binderDied() {
             // Clean up the state if the listener dies
-            mInInteractiveMode = false;
             mPinnedStackListener = null;
         }
     }
@@ -144,13 +136,13 @@
         mService = service;
         mDisplayContent = displayContent;
         mSnapAlgorithm = new PipSnapAlgorithm(service.mContext);
-        mMotionHelper = new PipMotionHelper(UiThread.getHandler());
         mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
         reloadResources();
     }
 
     void onConfigurationChanged() {
         reloadResources();
+        notifyMovementBoundsChanged(false /* fromImeAdjustment */);
     }
 
     /**
@@ -169,6 +161,10 @@
                 dpToPx(defaultSizeDp.getHeight(), mTmpMetrics));
         mScreenEdgeInsets = new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
                 dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
+        mMinAspectRatio = res.getFloat(
+                com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+        mMaxAspectRatio = res.getFloat(
+                com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
     }
 
     /**
@@ -179,20 +175,29 @@
             listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
             listener.onListenerRegistered(mCallbacks);
             mPinnedStackListener = listener;
-            notifyBoundsChanged(mIsImeShowing);
-            notifyMinimizeChanged(mIsMinimized);
-            notifySnapToEdgeChanged(mIsSnappingToEdge);
+            notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
+            // The movement bounds notification needs to be sent before the minimized state, since
+            // SystemUI may use the bounds to retore the minimized position
+            notifyMovementBoundsChanged(false /* fromImeAdjustment */);
             notifyActionsChanged(mActions);
+            notifyMinimizeChanged(mIsMinimized);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
     }
 
     /**
+     * @return whether the given {@param aspectRatio} is valid.
+     */
+    public boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
+        return mMinAspectRatio <= aspectRatio && aspectRatio <= mMaxAspectRatio;
+    }
+
+    /**
      * Returns the current bounds (or the default bounds if there are no current bounds) with the
      * specified aspect ratio.
      */
-    Rect getAspectRatioBounds(Rect stackBounds, float aspectRatio) {
+    Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio) {
         // Save the snap fraction, calculate the aspect ratio based on the current bounds
         final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
                 getMovementBounds(stackBounds));
@@ -236,27 +241,20 @@
         final Rect movementBounds = new Rect();
         getInsetBounds(movementBounds);
 
-        // Adjust the right/bottom to ensure the stack bounds never goes offscreen
-        movementBounds.right = Math.max(movementBounds.left, movementBounds.right -
-                stackBounds.width());
-        movementBounds.bottom = Math.max(movementBounds.top, movementBounds.bottom -
-                stackBounds.height());
-
         // Apply the movement bounds adjustments based on the current state
-        if (adjustForIme) {
-            if (mIsImeShowing) {
-                movementBounds.bottom -= mImeHeight;
-            }
-        }
+        mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
+                (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
         return movementBounds;
     }
 
     /**
+     * @param preChangeTargetBounds The final bounds of the stack if it is currently animating
      * @return the repositioned PIP bounds given it's pre-change bounds, and the new display
      *         content.
      */
-    Rect onDisplayChanged(Rect preChangeStackBounds, DisplayContent displayContent) {
-        final Rect postChangeStackBounds = new Rect(preChangeStackBounds);
+    Rect onDisplayChanged(Rect preChangeStackBounds, Rect preChangeTargetBounds,
+            DisplayContent displayContent) {
+        final Rect postChangeStackBounds = new Rect(preChangeTargetBounds);
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         if (!mDisplayInfo.equals(displayInfo)) {
             // Calculate the snap fraction of the current stack along the old movement bounds, and
@@ -277,6 +275,7 @@
                 mSnapAlgorithm.applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds,
                         displaySize, mStableInsets);
             }
+            notifyMovementBoundsChanged(false /* fromImeAdjustment */);
         }
         return postChangeStackBounds;
     }
@@ -290,42 +289,19 @@
             return;
         }
 
-        final Rect stackBounds = new Rect();
-        mService.getStackBounds(PINNED_STACK_ID, stackBounds);
-        final Rect prevMovementBounds = getMovementBounds(stackBounds);
         mIsImeShowing = adjustedForIme;
         mImeHeight = imeHeight;
-        if (mInInteractiveMode) {
-            // If the user is currently interacting with the PIP and the ime state changes, then
-            // don't adjust the bounds and defer that to after the interaction
-            notifyBoundsChanged(adjustedForIme /* adjustedForIme */);
-        } else {
-            // Otherwise, we can move the PIP to a sane location to ensure that it does not block
-            // the user from interacting with the IME
-            final Rect movementBounds = getMovementBounds(stackBounds);
-            final Rect toBounds = new Rect(stackBounds);
-            if (adjustedForIme) {
-                // IME visible
-                if (stackBounds.top == prevMovementBounds.bottom) {
-                    // If the PIP is resting on top of the IME, then adjust it with the hiding IME
-                    toBounds.offsetTo(toBounds.left, movementBounds.bottom);
-                } else {
-                    toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top));
-                }
-            } else {
-                // IME hidden
-                if (stackBounds.top == prevMovementBounds.bottom) {
-                    // If the PIP is resting on top of the IME, then adjust it with the hiding IME
-                    toBounds.offsetTo(toBounds.left, movementBounds.bottom);
-                }
-            }
-            if (!toBounds.equals(stackBounds)) {
-                if (mBoundsAnimator != null) {
-                    mBoundsAnimator.cancel();
-                }
-                mBoundsAnimator = mMotionHelper.createAnimationToBounds(stackBounds, toBounds);
-                mBoundsAnimator.start();
-            }
+        notifyImeVisibilityChanged(adjustedForIme, imeHeight);
+        notifyMovementBoundsChanged(true /* fromImeAdjustment */);
+    }
+
+    /**
+     * Sets the current aspect ratio.
+     */
+    void setAspectRatio(float aspectRatio) {
+        if (Float.compare(mAspectRatio, aspectRatio) != 0) {
+            mAspectRatio = aspectRatio;
+            notifyMovementBoundsChanged(false /* fromImeAdjustment */);
         }
     }
 
@@ -341,12 +317,12 @@
     }
 
     /**
-     * Notifies listeners that the PIP movement bounds have changed.
+     * Notifies listeners that the PIP needs to be adjusted for the IME.
      */
-    private void notifyBoundsChanged(boolean adjustedForIme) {
+    private void notifyImeVisibilityChanged(boolean imeVisible, int imeHeight) {
         if (mPinnedStackListener != null) {
             try {
-                mPinnedStackListener.onBoundsChanged(adjustedForIme);
+                mPinnedStackListener.onImeVisibilityChanged(imeVisible, imeHeight);
             } catch (RemoteException e) {
                 Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
             }
@@ -367,19 +343,6 @@
     }
 
     /**
-     * Notifies listeners that the PIP snap-to-edge state has changed.
-     */
-    private void notifySnapToEdgeChanged(boolean isSnappingToEdge) {
-        if (mPinnedStackListener != null) {
-            try {
-                mPinnedStackListener.onSnapToEdgeStateChanged(isSnappingToEdge);
-            } catch (RemoteException e) {
-                Slog.e(TAG_WM, "Error delivering snap-to-edge changed event.", e);
-            }
-        }
-    }
-
-    /**
      * Notifies listeners that the PIP actions have changed.
      */
     private void notifyActionsChanged(List<RemoteAction> actions) {
@@ -393,6 +356,26 @@
     }
 
     /**
+     * Notifies listeners that the PIP movement bounds have changed.
+     */
+    private void notifyMovementBoundsChanged(boolean fromImeAdjustement) {
+        if (mPinnedStackListener != null) {
+            try {
+                Rect insetBounds = new Rect();
+                getInsetBounds(insetBounds);
+                Rect normalBounds = getDefaultBounds();
+                if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
+                    transformBoundsToAspectRatio(normalBounds, mAspectRatio);
+                }
+                mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
+                        fromImeAdjustement);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering actions changed event.", e);
+            }
+        }
+    }
+
+    /**
      * @return the bounds on the screen that the PIP can be visible in.
      */
     private void getInsetBounds(Rect outRect) {
@@ -418,7 +401,6 @@
         pw.print(prefix + "  movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
         pw.println();
         pw.println(prefix + "  mIsImeShowing=" + mIsImeShowing);
-        pw.println(prefix + "  mInInteractiveMode=" + mInInteractiveMode);
         pw.println(prefix + "  mIsMinimized=" + mIsMinimized);
         if (mActions.isEmpty()) {
             pw.println(prefix + "  mActions=[]");
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index e2ea2c5..36d07e0 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -216,7 +216,28 @@
 
             final int displayId = mContainer.getDisplayContent().getDisplayId();
             final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
-            animateResizePinnedStack(toBounds, -1 /* duration */);
+            final Rect targetBounds = new Rect();
+            mContainer.getAnimatingBounds(targetBounds);
+            if (!toBounds.equals(targetBounds)) {
+                animateResizePinnedStack(toBounds, -1 /* duration */);
+            }
+
+            final PinnedStackController pinnedStackController =
+                    mContainer.getDisplayContent().getPinnedStackController();
+            pinnedStackController.setAspectRatio(
+                    pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+                            ? aspectRatio : -1f);
+        }
+    }
+
+    /** Sets the current picture-in-picture actions. */
+    public void setPictureInPictureActions(List<RemoteAction> actions) {
+        synchronized (mWindowMap) {
+            if (!mService.mSupportsPictureInPicture || mContainer == null) {
+                return;
+            }
+
+            mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
         }
     }
 
@@ -244,17 +265,6 @@
         }
     }
 
-    /** Sets the current picture-in-picture actions. */
-    public void setPictureInPictureActions(List<RemoteAction> actions) {
-        synchronized (mWindowMap) {
-            if (!mService.mSupportsPictureInPicture || mContainer == null) {
-                return;
-            }
-
-            mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
-        }
-    }
-
     private void getRawBounds(Rect outBounds) {
         if (mContainer.getRawFullscreen()) {
             outBounds.setEmpty();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d96e1ef..ab9a378 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -91,20 +91,16 @@
 
     private boolean mHomeTask;
 
-    // Whether this task is an on-top launcher task, which is determined by the root activity.
-    private boolean mIsOnTopLauncher;
-
     private TaskDescription mTaskDescription;
 
     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-            Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
-            boolean supportsPictureInPicture, boolean homeTask, TaskDescription taskDescription,
+            Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+            boolean homeTask, TaskDescription taskDescription,
             TaskWindowContainerController controller) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mService = service;
-        mIsOnTopLauncher = isOnTopLauncher;
         mResizeMode = resizeMode;
         mSupportsPictureInPicture = supportsPictureInPicture;
         mHomeTask = homeTask;
@@ -117,7 +113,7 @@
         return mStack != null ? mStack.getDisplayContent() : null;
     }
 
-    int getAdjustedAddPosition(int suggestedPosition) {
+    private int getAdjustedAddPosition(int suggestedPosition) {
         final int size = mChildren.size();
         if (suggestedPosition >= size) {
             return Math.min(size, suggestedPosition);
@@ -347,10 +343,6 @@
                 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
     }
 
-    boolean isOnTopLauncher() {
-        return mIsOnTopLauncher;
-    }
-
     boolean cropWindowsToStackBounds() {
         return isResizeable();
     }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 538f0d9..544d1e3 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -160,10 +160,6 @@
         return mChildren.size() > 1 && !mChildren.get(mChildren.size() - 1).isHomeTask();
     }
 
-    boolean topTaskIsOnTopLauncher() {
-        return mChildren.get(mChildren.size() - 1).isOnTopLauncher();
-    }
-
     /**
      * Set the bounds of the stack and its containing tasks.
      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
@@ -397,8 +393,10 @@
         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         switch (mStackId) {
             case PINNED_STACK_ID:
+                Rect targetBounds = new Rect();
+                getAnimatingBounds(targetBounds);
                 mTmpRect2 = mDisplayContent.getPinnedStackController().onDisplayChanged(mBounds,
-                        mDisplayContent);
+                        targetBounds, mDisplayContent);
                 break;
             case DOCKED_STACK_ID:
                 repositionDockedStackAfterRotation(mTmpRect2);
@@ -674,7 +672,9 @@
 
         // Update the pinned stack controller after the display info is updated
         if (mStackId == PINNED_STACK_ID) {
-            mDisplayContent.getPinnedStackController().onDisplayChanged(oldBounds,
+            Rect targetBounds = new Rect();
+            getAnimatingBounds(targetBounds);
+            mDisplayContent.getPinnedStackController().onDisplayChanged(oldBounds, targetBounds,
                     mDisplayContent);
         }
 
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 11667c0..efc2e11 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -51,17 +51,17 @@
     public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
             StackWindowController stackController, int userId, Rect bounds,
             Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
-            boolean homeTask, boolean isOnTopLauncher, boolean toTop, boolean showForAllUsers,
+            boolean homeTask, boolean toTop, boolean showForAllUsers,
             TaskDescription taskDescription) {
         this(taskId, listener, stackController, userId, bounds, overrideConfig, resizeMode,
-                supportsPictureInPicture, homeTask, isOnTopLauncher, toTop, showForAllUsers,
-                taskDescription, WindowManagerService.getInstance());
+                supportsPictureInPicture, homeTask, toTop, showForAllUsers, taskDescription,
+                WindowManagerService.getInstance());
     }
 
     public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
             StackWindowController stackController, int userId, Rect bounds,
             Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
-            boolean homeTask, boolean isOnTopLauncher, boolean toTop, boolean showForAllUsers,
+            boolean homeTask, boolean toTop, boolean showForAllUsers,
             TaskDescription taskDescription, WindowManagerService service) {
         super(listener, service);
         mTaskId = taskId;
@@ -78,7 +78,7 @@
             }
             EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
             final Task task = createTask(taskId, stack, userId, bounds, overrideConfig, resizeMode,
-                    supportsPictureInPicture, homeTask, isOnTopLauncher, taskDescription);
+                    supportsPictureInPicture, homeTask, taskDescription);
             final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
             stack.addTask(task, position, showForAllUsers, true /* moveParents */);
         }
@@ -87,9 +87,9 @@
     @VisibleForTesting
     Task createTask(int taskId, TaskStack stack, int userId, Rect bounds,
             Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
-            boolean homeTask, boolean isOnTopLauncher, TaskDescription taskDescription) {
-        return new Task(taskId, stack, userId, mService, bounds, overrideConfig, isOnTopLauncher,
-                resizeMode, supportsPictureInPicture, homeTask, taskDescription, this);
+            boolean homeTask, TaskDescription taskDescription) {
+        return new Task(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
+                supportsPictureInPicture, homeTask, taskDescription, this);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index e0c3d60..d56110c 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -59,7 +59,6 @@
     private ArrayDeque<WindowState> mPinnedWindows = new ArrayDeque<>();
     private ArrayDeque<WindowState> mDockedWindows = new ArrayDeque<>();
     private ArrayDeque<WindowState> mInputMethodWindows = new ArrayDeque<>();
-    private ArrayDeque<WindowState> mOnTopLauncherWindows = new ArrayDeque<>();
     private WindowState mDockDivider = null;
     private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>();
     private int mCurBaseLayer;
@@ -138,7 +137,6 @@
         mPinnedWindows.clear();
         mInputMethodWindows.clear();
         mDockedWindows.clear();
-        mOnTopLauncherWindows.clear();
         mReplacingWindows.clear();
         mDockDivider = null;
 
@@ -182,9 +180,6 @@
         if (task == null) {
             return;
         }
-        if (task.isOnTopLauncher()) {
-            mOnTopLauncherWindows.add(w);
-        }
         final TaskStack stack = task.mStack;
         if (stack == null) {
             return;
@@ -206,10 +201,6 @@
 
         layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
 
-        while (!mOnTopLauncherWindows.isEmpty()) {
-            layer = assignAndIncreaseLayerIfNeeded(mOnTopLauncherWindows.remove(), layer);
-        }
-
         // We know that we will be animating a relaunching window in the near future, which will
         // receive a z-order increase. We want the replaced window to immediately receive the same
         // treatment, e.g. to be above the dock divider.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 971794b..597e8b6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2829,36 +2829,6 @@
         mDockedStackCreateBounds = bounds;
     }
 
-    @Override
-    public Rect getPictureInPictureDefaultBounds(int displayId) {
-        synchronized (mWindowMap) {
-            if (!mSupportsPictureInPicture) {
-                return null;
-            }
-
-            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-            return displayContent.getPinnedStackController().getDefaultBounds();
-        }
-    }
-
-    @Override
-    public Rect getPictureInPictureMovementBounds(int displayId) {
-        synchronized (mWindowMap) {
-            if (!mSupportsPictureInPicture) {
-                return null;
-            }
-
-            final Rect stackBounds = new Rect();
-            getStackBounds(PINNED_STACK_ID, stackBounds);
-            if (stackBounds.isEmpty()) {
-                return stackBounds;
-            }
-
-            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-            return displayContent.getPinnedStackController().getMovementBounds(stackBounds);
-        }
-    }
-
     public Rect getPictureInPictureBounds(int displayId, float aspectRatio) {
         synchronized (mWindowMap) {
             if (!mSupportsPictureInPicture) {
@@ -2871,6 +2841,8 @@
                 return null;
             }
 
+            final PinnedStackController pinnedStackController =
+                    displayContent.getPinnedStackController();
             final TaskStack stack = displayContent.getStackById(PINNED_STACK_ID);
             if (stack != null) {
                 // If the stack exists, then use its final bounds to calculate the new aspect ratio
@@ -2879,13 +2851,23 @@
                 stack.getAnimatingBounds(stackBounds);
             } else {
                 // Otherwise, just calculate the aspect ratio bounds from the default bounds
-                stackBounds = displayContent.getPinnedStackController().getDefaultBounds();
+                stackBounds = pinnedStackController.getDefaultBounds();
             }
-            return displayContent.getPinnedStackController().getAspectRatioBounds(stackBounds,
-                    aspectRatio);
+
+            if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
+                return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio);
+            } else {
+                return stackBounds;
+            }
         }
     }
 
+    public boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) {
+        final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+        return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
+                aspectRatio);
+    }
+
     @Override
     public void getStackBounds(int stackId, Rect bounds) {
         synchronized (mWindowMap) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index b163abf..d2ea64c8 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -915,10 +915,15 @@
             if (attachedTransformation != null) {
                 tmpMatrix.postConcat(attachedTransformation.getMatrix());
             }
-            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
             if (appTransformation != null) {
                 tmpMatrix.postConcat(appTransformation.getMatrix());
             }
+
+            // The translation that applies the position of the window needs to be applied at the
+            // end in case that other translations include scaling. Otherwise the scaling will
+            // affect this translation. But it needs to be set before the screen rotation animation
+            // so the pivot point is at the center of the screen for all windows.
+            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
             if (screenAnimation) {
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index 545b3d7..703518d 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -70,7 +70,7 @@
 static void nativeInit(JNIEnv* env, jobject obj) {
     // TODO(b/31632518)
     if (gThermalModule == nullptr) {
-        gThermalModule = IThermal::getService("thermal");
+        gThermalModule = IThermal::getService();
     }
 
     if (gThermalModule == nullptr) {
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index e46490b..3120af5 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -26,18 +26,11 @@
 
 namespace android {
 
-static int start_sensor_service(void* /*unused*/) {
-    SensorService::instantiate();
-    return 0;
-}
-
 static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
     char propBuf[PROPERTY_VALUE_MAX];
     property_get("system_init.startsensorservice", propBuf, "1");
     if (strcmp(propBuf, "1") == 0) {
-        // Start the sensor service in a new thread
-        createThreadEtc(start_sensor_service, nullptr,
-                        "StartSensorThread", PRIORITY_FOREGROUND);
+        SensorService::instantiate();
     }
 }
 
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
index 517fce0..05ef0d1 100644
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ b/services/core/jni/com_android_server_location_ContextHubService.cpp
@@ -558,12 +558,12 @@
 void initContextHubService() {
     db.hubInfo.numHubs = 0;
 
-    db.hubInfo.contextHub = IContexthub::getService("context_hub_hal");
+    db.hubInfo.contextHub = IContexthub::getService("context_hub");
 
     if (db.hubInfo.contextHub == nullptr) {
         ALOGE("Could not load context hub hal");
     } else {
-        ALOGI("Loaded context hub hal");
+        ALOGI("Loaded context hub hal, isRemote %s", db.hubInfo.contextHub->isRemote() ? "TRUE" : "FALSE");
     }
 
     // Prep for storing app info
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 01a1efc..1578562 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -58,6 +58,7 @@
 static jmethodID method_reportGeofenceResumeStatus;
 static jmethodID method_reportMeasurementData;
 static jmethodID method_reportNavigationMessages;
+static jmethodID method_reportLocationBatch;
 
 /*
  * Save a pointer to JavaVm to attach/detach threads executing
@@ -80,6 +81,8 @@
 using android::hardware::gnss::V1_0::IAGnssRil;
 using android::hardware::gnss::V1_0::IAGnssRilCallback;
 using android::hardware::gnss::V1_0::IGnss;
+using android::hardware::gnss::V1_0::IGnssBatching;
+using android::hardware::gnss::V1_0::IGnssBatchingCallback;
 using android::hardware::gnss::V1_0::IGnssCallback;
 using android::hardware::gnss::V1_0::IGnssConfiguration;
 using android::hardware::gnss::V1_0::IGnssDebug;
@@ -100,6 +103,7 @@
 sp<IAGnssRil> agnssRilIface = nullptr;
 sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
 sp<IAGnss> agnssIface = nullptr;
+sp<IGnssBatching> gnssBatchingIface = nullptr;
 sp<IGnssDebug> gnssDebugIface = nullptr;
 sp<IGnssConfiguration> gnssConfigurationIface = nullptr;
 sp<IGnssNi> gnssNiIface = nullptr;
@@ -139,6 +143,7 @@
 class JavaObject {
  public:
     JavaObject(JNIEnv* env, const char* class_name);
+    JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_1);
     virtual ~JavaObject();
 
     template<class T>
@@ -159,6 +164,12 @@
     object_ = env_->NewObject(clazz_, ctor);
 }
 
+JavaObject::JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_1) : env_(env) {
+    clazz_ = env_->FindClass(class_name);
+    jmethodID ctor = env->GetMethodID(clazz_, "<init>", "(Ljava/lang/String;)V");
+    object_ = env_->NewObject(clazz_, ctor, env->NewStringUTF(sz_arg_1));
+}
+
 JavaObject::~JavaObject() {
     env_->DeleteLocalRef(clazz_);
 }
@@ -591,6 +602,7 @@
     env->CallVoidMethod(mCallbacksObj,
                         method_reportNavigationMessages,
                         navigationMessage);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
     env->DeleteLocalRef(navigationMessage);
     return Void();
 }
@@ -925,6 +937,81 @@
     return Void();
 }
 
+/*
+ * GnssBatchingCallback interface implements the callback methods
+ * required by the IGnssBatching interface.
+ */
+struct GnssBatchingCallback : public IGnssBatchingCallback {
+    /*
+    * Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback
+    * follow.
+    */
+    Return<void> gnssLocationBatchCb(
+        const ::android::hardware::hidl_vec<hardware::gnss::V1_0::GnssLocation> & locations)
+        override;
+ private:
+    jobject translateLocation(
+            JNIEnv* env, const hardware::gnss::V1_0::GnssLocation* location);
+};
+
+Return<void> GnssBatchingCallback::gnssLocationBatchCb(
+        const ::android::hardware::hidl_vec<hardware::gnss::V1_0::GnssLocation> & locations) {
+    JNIEnv* env = getJniEnv();
+
+    jobjectArray jLocations = env->NewObjectArray(locations.size(),
+            env->FindClass("android/location/Location"), nullptr);
+
+    for (uint16_t i = 0; i < locations.size(); ++i) {
+        jobject jLocation = translateLocation(env, &locations[i]);
+        env->SetObjectArrayElement(jLocations, i, jLocation);
+        env->DeleteLocalRef(jLocation);
+    }
+
+    env->CallVoidMethod(mCallbacksObj, method_reportLocationBatch, jLocations);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+    env->DeleteLocalRef(jLocations);
+
+    return Void();
+}
+
+// TODO: Use this common code to translate location for Geofencing and regular Location
+jobject GnssBatchingCallback::translateLocation(
+        JNIEnv* env, const hardware::gnss::V1_0::GnssLocation* location) {
+    JavaObject object(env, "android/location/Location", "gps");
+
+    uint16_t flags = static_cast<uint32_t>(location->gnssLocationFlags);
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_LAT_LONG) {
+        SET(Latitude, location->latitudeDegrees);
+        SET(Longitude, location->longitudeDegrees);
+    }
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_ALTITUDE) {
+        SET(Altitude, location->altitudeMeters);
+    }
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED) {
+        SET(Speed, location->speedMetersPerSec);
+    }
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING) {
+        SET(Bearing, location->bearingDegrees);
+    }
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+        SET(Accuracy, location->horizontalAccuracyMeters);
+    }
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        SET(VerticalAccuracyMeters, location->verticalAccuracyMeters);
+    }
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        SET(SpeedAccuracyMetersPerSecond, location->speedAccuracyMetersPerSecond);
+    }
+    if (flags & hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        SET(BearingAccuracyDegrees, location->bearingAccuracyDegrees);
+    }
+    SET(Time, location->timestamp);
+
+    return object.get();
+}
+
+
 static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
     method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFFFFJ)V");
     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
@@ -959,6 +1046,10 @@
             clazz,
             "reportNavigationMessage",
             "(Landroid/location/GnssNavigationMessage;)V");
+    method_reportLocationBatch = env->GetMethodID(
+            clazz,
+            "reportLocationBatch",
+            "([Landroid/location/Location;)V");
 
     /*
      * Save a pointer to JVM.
@@ -1033,6 +1124,13 @@
         } else {
             gnssGeofencingIface = gnssGeofencing;
         }
+
+        auto gnssBatching = gnssHal->getExtensionGnssBatching();
+        if (!gnssBatching.isOk()) {
+            ALOGD("Unable to get a handle to gnssBatching");
+        } else {
+            gnssBatchingIface = gnssBatching;
+        }
     } else {
       ALOGE("Unable to get GPS service\n");
     }
@@ -1704,6 +1802,67 @@
     }
 }
 
+static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
+    if (gnssBatchingIface == nullptr) {
+        return 0; // batching not supported, size = 0
+    }
+    auto result = gnssBatchingIface->getBatchSize();
+    if (result.isOk()) {
+        return static_cast<jint>(result);
+    } else {
+        return 0; // failure in binder, don't support batching
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) {
+    if (gnssBatchingIface == nullptr) {
+        return JNI_FALSE; // batching not supported
+    }
+    sp<IGnssBatchingCallback> gnssBatchingCbIface = new GnssBatchingCallback();
+
+    return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface));
+}
+
+static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) {
+    if (gnssBatchingIface == nullptr) {
+        return; // batching not supported
+    }
+    gnssBatchingIface->cleanup();
+}
+
+static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass,
+        jlong periodNanos, jboolean wakeOnFifoFull) {
+    if (gnssBatchingIface == nullptr) {
+        return JNI_FALSE; // batching not supported
+    }
+
+    IGnssBatching::Options options;
+    options.periodNanos = periodNanos;
+    if (wakeOnFifoFull) {
+        options.flags = static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL);
+    } else {
+        options.flags = 0;
+    }
+
+    return static_cast<jboolean>(gnssBatchingIface->start(options));
+}
+
+static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) {
+    if (gnssBatchingIface == nullptr) {
+        return; // batching not supported
+    }
+
+    gnssBatchingIface->flush();
+}
+
+static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) {
+    if (gnssBatchingIface == nullptr) {
+        return JNI_FALSE; // batching not supported
+    }
+
+    return gnssBatchingIface->stop();
+}
+
 static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", reinterpret_cast<void *>(
@@ -1829,6 +1988,27 @@
     {"native_set_emergency_supl_pdn",
             "(I)Z",
             reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)},
+    {"native_get_batch_size",
+            "()I",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_get_batch_size)},
+    {"native_init_batching",
+            "()Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)},
+    {"native_start_batch",
+            "(JZ)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_start_batch)},
+    {"native_flush_batch",
+            "()V",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_flush_batch)},
+    {"native_stop_batch",
+            "()Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_stop_batch)},
+    {"native_init_batching",
+            "()Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)},
+    {"native_cleanup_batching",
+            "()V",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_cleanup_batching)},
 };
 
 int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 578e0b3..5bd2e93 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -60,6 +60,7 @@
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
@@ -1885,8 +1886,14 @@
     }
 
     private void setDeviceOwnerSystemPropertyLocked() {
-        // Device owner may still be provisioned, do not set the read-only system property yet.
-        if (mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
+        final boolean deviceProvisioned =
+                mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+        // If the device is not provisioned and there is currently no device owner, do not set the
+        // read-only system property yet, since Device owner may still be provisioned. For Wear
+        // devices, if there is already a device owner then it's OK to set the property to true now,
+        // regardless the provision state.
+        final boolean isWatchWithDeviceOwner = mIsWatch && mOwners.hasDeviceOwner();
+        if (!isWatchWithDeviceOwner && !deviceProvisioned) {
             return;
         }
         // Still at the first stage of CryptKeeper double bounce, mOwners.hasDeviceOwner is
@@ -4296,7 +4303,7 @@
             if (!TextUtils.isEmpty(password)) {
                 mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
             } else {
-                mLockPatternUtils.clearLock(userHandle);
+                mLockPatternUtils.clearLock(null, userHandle);
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
@@ -6151,8 +6158,12 @@
                 intent.setComponent(mOwners.getDeviceOwnerComponent());
                 intent.setDataAndType(bugreportUri, RemoteBugreportUtils.BUGREPORT_MIMETYPE);
                 intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
-                mContext.grantUriPermission(mOwners.getDeviceOwnerComponent().getPackageName(),
-                        bugreportUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+                LocalServices.getService(ActivityManagerInternal.class)
+                        .grantUriPermissionFromIntent(Process.SHELL_UID,
+                                mOwners.getDeviceOwnerComponent().getPackageName(),
+                                intent, mOwners.getDeviceOwnerUserId());
                 mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
             }
         } catch (FileNotFoundException e) {
@@ -6706,6 +6717,8 @@
         policy.mDelegationMap.clear();
         policy.mStatusBarDisabled = false;
         policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
+        policy.mAffiliationIds.clear();
+        policy.mLockTaskPackages.clear();
         saveSettingsLocked(userId);
 
         try {
@@ -8610,9 +8623,6 @@
         }
     }
 
-    /**
-     * This function returns the list of components allowed to start the task lock mode.
-     */
     @Override
     public String[] getLockTaskPackages(ComponentName who) {
         Preconditions.checkNotNull(who, "ComponentName is null");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b911d2d..83e209d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -125,8 +125,13 @@
 public final class SystemServer {
     private static final String TAG = "SystemServer";
 
+    // Tag for timing measurement of main thread.
+    private static final String SYSTEM_SERVER_TIMING_TAG = "SystemServerTiming";
+    // Tag for timing measurement of non-main asynchronous operations.
+    private static final String SYSTEM_SERVER_TIMING_ASYNC_TAG = SYSTEM_SERVER_TIMING_TAG + "Async";
+
     private static final BootTimingsTraceLog BOOT_TIMINGS_TRACE_LOG
-            = new BootTimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
+            = new BootTimingsTraceLog(SYSTEM_SERVER_TIMING_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
 
     private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
     private static final String ENCRYPTED_STATE = "1";
@@ -149,6 +154,8 @@
             "com.android.server.voiceinteraction.VoiceInteractionManagerService";
     private static final String PRINT_MANAGER_SERVICE_CLASS =
             "com.android.server.print.PrintManagerService";
+    private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS =
+            "com.android.server.print.CompanionDeviceManagerService";
     private static final String USB_SERVICE_CLASS =
             "com.android.server.usb.UsbService$Lifecycle";
     private static final String MIDI_SERVICE_CLASS =
@@ -227,8 +234,11 @@
     private boolean mFirstBoot;
     private final boolean mRuntimeRestart;
 
+    private static final String START_SENSOR_SERVICE = "StartSensorService";
+    private Future<?> mSensorServiceStart;
+
     /**
-     * Start the sensor service.
+     * Start the sensor service. This is a blocking call and can take time.
      */
     private static native void startSensorService();
 
@@ -382,7 +392,7 @@
             MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
             final int MAX_UPTIME_MILLIS = 60 * 1000;
             if (uptimeMillis > MAX_UPTIME_MILLIS) {
-                Slog.wtf("SystemServerTiming",
+                Slog.wtf(SYSTEM_SERVER_TIMING_TAG,
                         "SystemServer init took too long. uptimeMillis=" + uptimeMillis);
             }
         }
@@ -584,9 +594,15 @@
 
         // The sensor service needs access to package manager service, app ops
         // service, and permissions service, therefore we start it after them.
-        traceBeginAndSlog("StartSensorService");
-        startSensorService();
-        traceEnd();
+        // Start sensor service in a separate thread. Completion should be checked
+        // before using it.
+        mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
+            BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
+                    SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceLog.traceBegin(START_SENSOR_SERVICE);
+            startSensorService();
+            traceLog.traceEnd();
+        }, START_SENSOR_SERVICE);
     }
 
     /**
@@ -742,6 +758,9 @@
             traceEnd();
 
             traceBeginAndSlog("StartWindowManagerService");
+            // WMS needs sensor service ready
+            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
+            mSensorServiceStart = null;
             wm = WindowManagerService.main(context, inputManager,
                     mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                     !mFirstBoot, mOnlyCore, new PhoneWindowManager());
@@ -1333,6 +1352,10 @@
                 traceEnd();
             }
 
+            traceBeginAndSlog("StartCompanionDeviceManager");
+            mSystemServiceManager.startService(COMPANION_DEVICE_MANAGER_SERVICE_CLASS);
+            traceEnd();
+
             traceBeginAndSlog("StartRestrictionManager");
             mSystemServiceManager.startService(RestrictionsManagerService.class);
             traceEnd();
@@ -1590,7 +1613,7 @@
                 webviewPrep = SystemServerInitThreadPool.get().submit(() -> {
                     Slog.i(TAG, WEBVIEW_PREPARATION);
                     BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
-                            "SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
+                            SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
                     traceLog.traceBegin(WEBVIEW_PREPARATION);
                     mWebViewUpdateService.prepareWebViewInSystemServer();
                     traceLog.traceEnd();
@@ -1651,13 +1674,13 @@
             Watchdog.getInstance().start();
             traceEnd();
 
-            if (webviewPrep != null) {
-                ConcurrentUtils.waitForFutureNoInterrupt(webviewPrep, WEBVIEW_PREPARATION);
-            }
-
             // It is now okay to let the various system services start their
             // third party code...
             traceBeginAndSlog("PhaseThirdPartyAppsCanStart");
+            // confirm webview completion before starting 3rd party
+            if (webviewPrep != null) {
+                ConcurrentUtils.waitForFutureNoInterrupt(webviewPrep, WEBVIEW_PREPARATION);
+            }
             mSystemServiceManager.startBootPhase(
                     SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
             traceEnd();
diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
new file mode 100644
index 0000000..9824c1d
--- /dev/null
+++ b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
@@ -0,0 +1,147 @@
+/*
+ * 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.server.print;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.PendingIntent;
+import android.companion.AssociationRequest;
+import android.companion.ICompanionDeviceManager;
+import android.companion.ICompanionDeviceManagerService;
+import android.companion.IOnAssociateCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+//TODO move to own package!
+/** @hide */
+public class CompanionDeviceManagerService extends SystemService {
+
+    private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
+            "com.android.companiondevicemanager", ".DeviceDiscoveryService");
+
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "CompanionDeviceManagerService";
+
+    private final CompanionDeviceManagerImpl mImpl;
+
+    public CompanionDeviceManagerService(Context context) {
+        super(context);
+        mImpl = new CompanionDeviceManagerImpl();
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
+    }
+
+    class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
+
+        @Override
+        public void associate(
+                AssociationRequest request,
+                IOnAssociateCallback callback,
+                String callingPackage) throws RemoteException {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback
+                        + ", callingPackage = " + callingPackage + ")");
+            }
+            checkNotNull(request);
+            checkNotNull(callback);
+            final long callingIdentity = Binder.clearCallingIdentity();
+            try {
+                //TODO bindServiceAsUser
+                getContext().bindService(
+                        new Intent().setComponent(SERVICE_TO_BIND_TO),
+                        getServiceConnection(request, callback, callingPackage),
+                        Context.BIND_AUTO_CREATE);
+            } finally {
+                Binder.restoreCallingIdentity(callingIdentity);
+            }
+        }
+    }
+
+    private ServiceConnection getServiceConnection(
+            final AssociationRequest<?> request,
+            final IOnAssociateCallback callback,
+            final String callingPackage) {
+        return new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG,
+                            "onServiceConnected(name = " + name + ", service = "
+                                    + service + ")");
+                }
+                try {
+                    ICompanionDeviceManagerService.Stub
+                            .asInterface(service)
+                            .startDiscovery(
+                                    request,
+                                    getCallback(callingPackage, callback),
+                                    callingPackage);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                if (DEBUG) Log.i(LOG_TAG, "onServiceDisconnected(name = " + name + ")");
+            }
+        };
+    }
+
+    private IOnAssociateCallback.Stub getCallback(
+            String callingPackage,
+            IOnAssociateCallback propagateTo) {
+        return new IOnAssociateCallback.Stub() {
+
+            @Override
+            public void onSuccess(PendingIntent launcher)
+                    throws RemoteException {
+                if (DEBUG) Log.i(LOG_TAG, "onSuccess(launcher = " + launcher + ")");
+                recordSpecialPriviledgesForPackage(callingPackage);
+                propagateTo.onSuccess(launcher);
+            }
+
+            @Override
+            public void onFailure(CharSequence reason) throws RemoteException {
+                if (DEBUG) Log.i(LOG_TAG, "onFailure()");
+                propagateTo.onFailure(reason);
+            }
+        };
+    }
+
+    void recordSpecialPriviledgesForPackage(String priviledgedPackage) {
+        //TODO Show dialog before recording notification access
+//        final SettingStringHelper setting =
+//                new SettingStringHelper(
+//                        getContext().getContentResolver(),
+//                        Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+//                        Binder.getCallingUid());
+//        setting.write(ColonDelimitedSet.OfStrings.add(setting.read(), priviledgedPackage));
+    }
+}
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index f30c466..f943ee2c 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -541,6 +541,8 @@
     }
 
     private void stopDemoMode() {
+        mDeviceInDemoMode = false;
+        mIsCarrierDemoMode = false;
         mPreloadAppsInstaller = null;
         mCameraIdsWithFlash = null;
         mInjector.destroyWakeLock();
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 9202cce..15f7557 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -20,7 +20,6 @@
 import static junit.framework.Assert.assertTrue;
 
 import com.android.server.lights.Light;
-import com.android.server.statusbar.StatusBarManagerInternal;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -224,7 +223,7 @@
             } else {
                 builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF);
             }
-            channel.setLights(true);
+            channel.enableLights(true);
         }
         builder.setDefaults(defaults);
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index aa08b41..064ab0a 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -112,6 +112,7 @@
         Notification n2 = new Notification.Builder(mContext)
                 .setCategory(Notification.CATEGORY_CALL)
                 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .setColorized(true /* colorized */)
                 .build();
         mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "highcall", callUid, callUid, n2,
@@ -186,10 +187,10 @@
         final List<NotificationRecord> expected = new ArrayList<>();
         expected.add(mRecordHighCall);
         expected.add(mRecordDefaultMedia);
-        expected.add(mRecordStarredContact);
-        expected.add(mRecordContact);
         expected.add(mRecordInlineReply);
         expected.add(mRecordSms);
+        expected.add(mRecordStarredContact);
+        expected.add(mRecordContact);
         expected.add(mRecordEmail);
         expected.add(mRecordUrgent);
         expected.add(mRecordCheater);
@@ -207,14 +208,19 @@
     @Test
     public void testMessaging() throws Exception {
         NotificationComparator comp = new NotificationComparator(mContext);
-        assertTrue(comp.isImportantMessaging(mRecordStarredContact));
-        assertTrue(comp.isImportantMessaging(mRecordContact));
         assertTrue(comp.isImportantMessaging(mRecordInlineReply));
         assertTrue(comp.isImportantMessaging(mRecordSms));
         assertFalse(comp.isImportantMessaging(mRecordEmail));
         assertFalse(comp.isImportantMessaging(mRecordCheater));
     }
 
+    @Test
+    public void testPeople() throws Exception {
+        NotificationComparator comp = new NotificationComparator(mContext);
+        assertTrue(comp.isImportantPeople(mRecordStarredContact));
+        assertTrue(comp.isImportantPeople(mRecordContact));
+    }
+
     private NotificationChannel getDefaultChannel() {
         return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
                 NotificationManager.IMPORTANCE_LOW);
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 0ec368f..13d6c5d 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -33,6 +33,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.graphics.Color;
 import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.Build;
@@ -137,10 +138,11 @@
                 defaults |= Notification.DEFAULT_LIGHTS;
             } else {
                 builder.setLights(CUSTOM_LIGHT.color, CUSTOM_LIGHT.onMs, CUSTOM_LIGHT.offMs);
+                channel.setLightColor(Color.BLUE);
             }
-            channel.setLights(true);
+            channel.enableLights(true);
         } else {
-            channel.setLights(false);
+            channel.enableLights(false);
         }
 
         builder.setDefaults(defaults);
@@ -316,7 +318,7 @@
 
     @Test
     public void testLights_locked_preUpgrade() throws Exception {
-        defaultChannel.setLights(true);
+        defaultChannel.enableLights(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
         StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
@@ -327,7 +329,7 @@
     }
 
     @Test
-    public void testLights_upgrade() throws Exception {
+    public void testLights_upgrade_defaultLights() throws Exception {
         int defaultLightColor = mMockContext.getResources().getColor(
                 com.android.internal.R.color.config_defaultNotificationColor);
         int defaultLightOn = mMockContext.getResources().getInteger(
@@ -339,6 +341,22 @@
                 defaultLightColor, defaultLightOn, defaultLightOff);
         StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                true /* lights */, true /*defaultLights */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        assertEquals(expected, record.getLight());
+    }
+
+    @Test
+    public void testLights_upgrade() throws Exception {
+        int defaultLightOn = mMockContext.getResources().getInteger(
+                com.android.internal.R.integer.config_defaultNotificationLedOn);
+        int defaultLightOff = mMockContext.getResources().getInteger(
+                com.android.internal.R.integer.config_defaultNotificationLedOff);
+
+        NotificationRecord.Light expected = new NotificationRecord.Light(
+                Color.BLUE, defaultLightOn, defaultLightOff);
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(expected, record.getLight());
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 9fa46d1..9ea9ce9 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.fail;
 
@@ -36,6 +38,7 @@
 import android.app.NotificationManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.graphics.Color;
 import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.Build;
@@ -55,6 +58,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -167,7 +171,7 @@
 
     private NotificationChannel getDefaultChannel() {
         return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
-                NotificationManager.IMPORTANCE_LOW);
+                IMPORTANCE_LOW);
     }
 
     private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, String... channelIds)
@@ -200,6 +204,7 @@
         assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
         assertEquals(expected.getGroup(), actual.getGroup());
         assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes());
+        assertEquals(expected.getLightColor(), actual.getLightColor());
     }
 
     @Test
@@ -258,14 +263,15 @@
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel2 =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
-        channel2.setLights(true);
+        channel2.enableLights(true);
         channel2.setBypassDnd(true);
         channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel2.enableVibration(true);
         channel2.setGroup(ncg.getId());
         channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
+        channel2.setLightColor(Color.BLUE);
 
         mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
         mHelper.createNotificationChannel(pkg, uid, channel1, true);
@@ -291,10 +297,26 @@
                 mHelper.getNotificationChannel(pkg, uid, channel2.getId(), false));
         assertNotNull(mHelper.getNotificationChannel(
                 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false));
-        assertEquals(ncg.getId(),
-                mHelper.getNotificationChannelGroups(pkg, uid, false).getList().get(0).getId());
-        assertEquals(channel2.getGroup(), mHelper.getNotificationChannelGroups(
-                pkg, uid, false).getList().get(0).getChannels().get(0).getGroup());
+
+        List<NotificationChannelGroup> actualGroups =
+                mHelper.getNotificationChannelGroups(pkg, uid, false).getList();
+        boolean foundNcg = false;
+        for (NotificationChannelGroup actual : actualGroups) {
+            if (ncg.getId().equals(actual.getId())) {
+                foundNcg = true;
+                 break;
+            }
+        }
+        assertTrue(foundNcg);
+
+        boolean foundChannel2Group = false;
+        for (NotificationChannelGroup actual : actualGroups) {
+            if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
+                foundChannel2Group = true;
+                break;
+            }
+        }
+        assertTrue(foundChannel2Group);
     }
 
     @Test
@@ -329,7 +351,7 @@
 
         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
                 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
-        defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        defaultChannel.setImportance(IMPORTANCE_LOW);
         mHelper.updateNotificationChannel(pkg, uid, defaultChannel);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(),
@@ -341,7 +363,7 @@
         parser.nextTag();
         mHelper.readXml(parser, false);
 
-        assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
+        assertEquals(IMPORTANCE_LOW, mHelper.getNotificationChannel(
                 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
     }
 
@@ -373,7 +395,7 @@
         final NotificationChannel updated2 = mHelper.getNotificationChannel(
                 pkg2, uid2, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         // clamped
-        assertEquals(NotificationManager.IMPORTANCE_LOW, updated2.getImportance());
+        assertEquals(IMPORTANCE_LOW, updated2.getImportance());
         assertFalse(updated2.canBypassDnd());
         assertEquals(Notification.VISIBILITY_PRIVATE, updated2.getLockscreenVisibility());
         assertEquals(NotificationChannel.USER_LOCKED_VISIBILITY, updated2.getUserLockedFields());
@@ -385,7 +407,7 @@
 
         try {
             mHelper.createNotificationChannel(pkg, uid,
-                    new NotificationChannel(pkg, "", NotificationManager.IMPORTANCE_LOW), true);
+                    new NotificationChannel(pkg, "", IMPORTANCE_LOW), true);
             fail("Channel creation should fail");
         } catch (IllegalArgumentException e) {
             // pass
@@ -396,7 +418,7 @@
     public void testUpdate_userLockedImportance() throws Exception {
         // all fields locked by user
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
 
         mHelper.createNotificationChannel(pkg, uid, channel, false);
@@ -415,7 +437,7 @@
     public void testUpdate_userLockedVisibility() throws Exception {
         // all fields locked by user
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
 
@@ -436,8 +458,8 @@
     public void testUpdate_userLockedVibration() throws Exception {
         // all fields locked by user
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
-        channel.setLights(false);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+        channel.enableLights(false);
         channel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
 
         mHelper.createNotificationChannel(pkg, uid, channel, false);
@@ -458,8 +480,8 @@
     public void testUpdate_userLockedLights() throws Exception {
         // all fields locked by user
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
-        channel.setLights(false);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+        channel.enableLights(false);
         channel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
 
         mHelper.createNotificationChannel(pkg, uid, channel, false);
@@ -467,7 +489,7 @@
         // same id, try to update
         final NotificationChannel channel2 =
                 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
-        channel2.setLights(true);
+        channel2.enableLights(true);
 
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
@@ -479,7 +501,7 @@
     public void testUpdate_userLockedPriority() throws Exception {
         // all fields locked by user
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setBypassDnd(true);
         channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
 
@@ -500,7 +522,7 @@
     public void testUpdate_userLockedRingtone() throws Exception {
         // all fields locked by user
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
         channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
 
@@ -520,7 +542,7 @@
     @Test
     public void testUpdate_userLockedBadge() throws Exception {
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setShowBadge(true);
         channel.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
 
@@ -540,9 +562,9 @@
     public void testUpdate() throws Exception {
         // no fields locked by user
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
-        channel.setLights(true);
+        channel.enableLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
 
@@ -552,7 +574,7 @@
         final NotificationChannel channel2 =
                 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
         channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes);
-        channel2.setLights(false);
+        channel2.enableLights(false);
         channel2.setBypassDnd(false);
         channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
 
@@ -572,9 +594,9 @@
     @Test
     public void testCreateChannel_CannotChangeHiddenFields() throws Exception {
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
-        channel.setLights(true);
+        channel.enableLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
@@ -599,9 +621,9 @@
     @Test
     public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception {
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
-        channel.setLights(true);
+        channel.enableLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
@@ -626,9 +648,9 @@
     @Test
     public void testGetDeletedChannel() throws Exception {
         NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
-        channel.setLights(true);
+        channel.enableLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.enableVibration(true);
@@ -652,9 +674,9 @@
     public void testGetDeletedChannels() throws Exception {
         Map<String, NotificationChannel> channelMap = new HashMap<>();
         NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
-        channel.setLights(true);
+        channel.enableLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
         channel.enableVibration(true);
@@ -691,7 +713,7 @@
     @Test
     public void testUpdateDeletedChannels() throws Exception {
         NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         mHelper.createNotificationChannel(pkg, uid, channel, true);
 
         mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
@@ -716,7 +738,7 @@
     public void testCreateDeletedChannel() throws Exception {
         long[] vibration = new long[]{100, 67, 145, 156};
         NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setVibrationPattern(vibration);
 
         mHelper.createNotificationChannel(pkg, uid, channel, true);
@@ -737,7 +759,7 @@
     public void testCreateChannel_alreadyExists() throws Exception {
         long[] vibration = new long[]{100, 67, 145, 156};
         NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setVibrationPattern(vibration);
 
         mHelper.createNotificationChannel(pkg, uid, channel, true);
@@ -758,7 +780,7 @@
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel2 =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
 
         mHelper.createNotificationChannel(pkg, uid, channel1, true);
         mHelper.createNotificationChannel(pkg, uid, channel2, false);
@@ -897,4 +919,29 @@
             }
         }
     }
+
+    @Test
+    public void testGetChannelGroups_noSideEffects() throws Exception {
+        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+        mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
+
+        NotificationChannel channel1 =
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+        channel1.setGroup(ncg.getId());
+        mHelper.createNotificationChannel(pkg, uid, channel1, true);
+        mHelper.getNotificationChannelGroups(pkg, uid, true).getList();
+
+        channel1.setImportance(IMPORTANCE_LOW);
+        mHelper.updateNotificationChannel(pkg, uid, channel1);
+
+        List<NotificationChannelGroup> actual =
+                mHelper.getNotificationChannelGroups(pkg, uid, true).getList();
+
+        assertEquals(2, actual.size());
+        for (NotificationChannelGroup group : actual) {
+            if (Objects.equals(group.getId(),ncg.getId())) {
+                assertEquals(1, group.getChannels().size());
+            }
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java
index d6ee367..84ebb19 100644
--- a/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java
@@ -137,6 +137,6 @@
         assertEquals(0, mCommand.exec(new Binder(), in, out, err,
                 new String[] { "clear", "--old", "1234" },
                 mShellCallback, mResultReceiver));
-        verify(mLockPatternUtils).clearLock(mUserId);
+        verify(mLockPatternUtils).clearLock("1234", mUserId);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 9645916..3f34d4f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -76,6 +76,7 @@
 import android.net.INetworkPolicyListener;
 import android.net.INetworkStatsService;
 import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkPolicy;
@@ -975,7 +976,8 @@
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
-        return new NetworkState(info, prop, null, null, null, TEST_SSID);
+        final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+        return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
     }
 
     private void expectCurrentTime() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 152b9c9..3a88e9c 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -117,6 +117,8 @@
     private static final String SSID = "ssid";
     private static final String SSID_2 = "ssid_2";
     private static final String SSID_3 = "ssid_3";
+    private static final ComponentName RECOMMENDATION_SERVICE_COMP =
+            new ComponentName("newPackageName", "newScoringServiceClass");
     private static final ScoredNetwork SCORED_NETWORK =
             new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
                     null /* rssiCurve*/);
@@ -124,7 +126,7 @@
             new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
                     null /* rssiCurve*/);
     private static final NetworkScorerAppData NEW_SCORER =
-        new NetworkScorerAppData("newPackageName", 1, "newScoringServiceClass");
+        new NetworkScorerAppData(1, RECOMMENDATION_SERVICE_COMP);
 
     @Mock private NetworkScorerAppManager mNetworkScorerAppManager;
     @Mock private Context mContext;
@@ -203,8 +205,7 @@
 
         verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
                 new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
-                        .setComponent(new ComponentName(NEW_SCORER.packageName,
-                                NEW_SCORER.recommendationServiceClassName))),
+                        .setComponent(RECOMMENDATION_SERVICE_COMP)),
                 any(ServiceConnection.class),
                 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
                 eq(UserHandle.SYSTEM));
@@ -657,7 +658,8 @@
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
         mNetworkScoreService.systemRunning();
 
-        assertEquals(NEW_SCORER.packageName, mNetworkScoreService.getActiveScorerPackage());
+        assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
+                mNetworkScoreService.getActiveScorerPackage());
     }
 
     @Test
@@ -827,10 +829,52 @@
         assertEquals(expectedList, actualList);
     }
 
+    @Test
+    public void testGetActiveScorer_notConnected_canRequestScores() throws Exception {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        assertNull(mNetworkScoreService.getActiveScorer());
+    }
+
+    @Test
+    public void testGetActiveScorer_notConnected_canNotRequestScores() throws Exception {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        try {
+            mNetworkScoreService.getActiveScorer();
+            fail("SecurityException expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testGetActiveScorer_connected_canRequestScores()
+            throws Exception {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        NetworkScorerAppData expectedAppData =
+                new NetworkScorerAppData(Binder.getCallingUid(), RECOMMENDATION_SERVICE_COMP);
+        bindToScorer(expectedAppData);
+        assertEquals(expectedAppData, mNetworkScoreService.getActiveScorer());
+    }
+
+    @Test
+    public void testGetActiveScorer_connected_canNotRequestScores()
+            throws Exception {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        bindToScorer(false);
+        try {
+            mNetworkScoreService.getActiveScorer();
+            fail("SecurityException expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
     // "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
     private void injectProvider() {
-        final ComponentName componentName = new ComponentName(NEW_SCORER.packageName,
-                NEW_SCORER.recommendationServiceClassName);
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
         when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
                 isA(UserHandle.class))).thenAnswer(new Answer<Boolean>() {
@@ -840,7 +884,8 @@
                 when(mockBinder.queryLocalInterface(anyString()))
                         .thenReturn(mRecommendationProvider);
                 invocation.getArgumentAt(1, ServiceConnection.class)
-                        .onServiceConnected(componentName, mockBinder);
+                        .onServiceConnected(NEW_SCORER.getRecommendationServiceComponent(),
+                                mockBinder);
                 return true;
             }
         });
@@ -848,9 +893,13 @@
     }
 
     private void bindToScorer(boolean callerIsScorer) {
-        final int callingUid = callerIsScorer ? Binder.getCallingUid() : 0;
-        NetworkScorerAppData appData = new NetworkScorerAppData(NEW_SCORER.packageName,
-                callingUid, NEW_SCORER.recommendationServiceClassName);
+        final int callingUid = callerIsScorer ? Binder.getCallingUid() : Binder.getCallingUid() + 1;
+        NetworkScorerAppData appData =
+                new NetworkScorerAppData(callingUid, RECOMMENDATION_SERVICE_COMP);
+        bindToScorer(appData);
+    }
+
+    private void bindToScorer(NetworkScorerAppData appData) {
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
         when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
                 isA(UserHandle.class))).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 213fb27..e433b60 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -190,6 +190,8 @@
         mAms.addAccountExplicitly(a31, "p31", null);
         mAms.addAccountExplicitly(a32, "p32", null);
 
+        String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
         Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(6, accounts.length);
@@ -306,6 +308,8 @@
 
     @SmallTest
     public void testRemovedAccountSync() throws Exception {
+        String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
         unlockSystemUser();
         Account a1 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
         Account a2 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
@@ -347,6 +351,8 @@
 
         // Start testing
         unlockSystemUser();
+        String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
         Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
         assertEquals("1 account should be migrated", 1, accounts.length);
         assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name);
@@ -1048,7 +1054,6 @@
         // Assert finishSessionAsUser added calling uid and pid into the sessionBundle
         assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_UID));
         assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_PID));
-        // Assert App bundle data overrides sessionBundle data
         assertEquals(sessionBundle.getString(
                 AccountManager.KEY_ANDROID_PACKAGE_NAME), "APCT.package");
 
@@ -1387,6 +1392,9 @@
 
     @SmallTest
     public void testRemoveAccountAsUserRemovalAllowed() throws Exception {
+        String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
         unlockSystemUser();
         mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p1", null);
         Account[] addedAccounts =
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
index 2e045ff..2cb8af4 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
@@ -355,49 +355,49 @@
     @Test
     public void testVisibilityFindSetDelete() {
         long accId = 10;
-        int uid1 = 100500;
-        int uid2 = 100501;
+        String packageName1 = "com.example.one";
+        String packageName2 = "com.example.two";
         Account account = new Account("name", "example.com");
-        assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+        assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
 
         mAccountsDb.insertDeAccount(account, accId);
-        assertNull(mAccountsDb.findAccountVisibility(account, uid1));
-        assertNull(mAccountsDb.findAccountVisibility(accId, uid1));
+        assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
+        assertNull(mAccountsDb.findAccountVisibility(accId, packageName1));
 
-        mAccountsDb.setAccountVisibility(accId, uid1, 1);
-        assertEquals(mAccountsDb.findAccountVisibility(account, uid1), Integer.valueOf(1));
-        assertEquals(mAccountsDb.findAccountVisibility(accId, uid1), Integer.valueOf(1));
+        mAccountsDb.setAccountVisibility(accId, packageName1, 1);
+        assertEquals(mAccountsDb.findAccountVisibility(account, packageName1), Integer.valueOf(1));
+        assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1));
 
-        mAccountsDb.setAccountVisibility(accId, uid2, 2);
-        assertEquals(mAccountsDb.findAccountVisibility(accId, uid2), Integer.valueOf(2));
+        mAccountsDb.setAccountVisibility(accId, packageName2, 2);
+        assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(2));
 
-        mAccountsDb.setAccountVisibility(accId, uid2, 3);
-        assertEquals(mAccountsDb.findAccountVisibility(accId, uid2), Integer.valueOf(3));
+        mAccountsDb.setAccountVisibility(accId, packageName2, 3);
+        assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(3));
 
-        Map<Integer, Integer> vis = mAccountsDb.findAllVisibilityValuesForAccount(account);
+        Map<String, Integer> vis = mAccountsDb.findAllVisibilityValuesForAccount(account);
         assertEquals(vis.size(), 2);
-        assertEquals(vis.get(uid1), Integer.valueOf(1));
-        assertEquals(vis.get(uid2), Integer.valueOf(3));
+        assertEquals(vis.get(packageName1), Integer.valueOf(1));
+        assertEquals(vis.get(packageName2), Integer.valueOf(3));
 
-        assertTrue(mAccountsDb.deleteAccountVisibilityForUid(uid1));
-        assertNull(mAccountsDb.findAccountVisibility(accId, uid1));
-        assertFalse(mAccountsDb.deleteAccountVisibilityForUid(uid1)); // Already deleted.
+        assertTrue(mAccountsDb.deleteAccountVisibilityForPackage(packageName1));
+        assertNull(mAccountsDb.findAccountVisibility(accId, packageName1));
+        assertFalse(mAccountsDb.deleteAccountVisibilityForPackage(packageName1)); // 2nd attempt.
     }
 
     @Test
     public void testVisibilityCleanupTrigger() {
         long accId = 10;
-        int uid1 = 100500;
+        String packageName1 = "com.example.one";
         Account account = new Account("name", "example.com");
 
-        assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+        assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
         mAccountsDb.insertDeAccount(account, accId);
-        assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+        assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
 
-        mAccountsDb.setAccountVisibility(accId, uid1, 1);
-        assertEquals(mAccountsDb.findAccountVisibility(accId, uid1), Integer.valueOf(1));
+        mAccountsDb.setAccountVisibility(accId, packageName1, 1);
+        assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1));
 
         assertTrue(mAccountsDb.deleteDeAccount(accId)); // Trigger should remove visibility.
-        assertNull(mAccountsDb.findAccountVisibility(account, uid1));
+        assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 7df638c..6fb65d5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2089,9 +2089,19 @@
         assertTrue(dpm.getAffiliationIds(admin2).isEmpty());
         assertFalse(dpm.isAffiliatedUser());
 
+        // Set affiliation ids again, then clear PO to check that the user becomes unaffiliated
+        dpm.setAffiliationIds(admin2, userAffiliationIds);
+        assertTrue(dpm.isAffiliatedUser());
+        dpm.clearProfileOwner(admin2);
+        assertFalse(dpm.isAffiliatedUser());
+
         // Check that the system user remains affiliated.
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         assertTrue(dpm.isAffiliatedUser());
+
+        // Clear the device owner - the user becomes unaffiliated.
+        clearDeviceOwner();
+        assertFalse(dpm.isAffiliatedUser());
     }
 
     public void testGetUserProvisioningState_defaultResult() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e30bd5d..e5640c7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -309,6 +309,7 @@
 
         // Sanity check for InstrumentationInfo.
         assertEquals(a.info.targetPackage, b.info.targetPackage);
+        assertEquals(a.info.targetProcess, b.info.targetProcess);
         assertEquals(a.info.sourceDir, b.info.sourceDir);
         assertEquals(a.info.publicSourceDir, b.info.publicSourceDir);
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
new file mode 100644
index 0000000..7a676e25
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
@@ -0,0 +1,273 @@
+/*
+ * 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.server.pm;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.FileUtils;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * <p>Run with:<pre>
+ * m FrameworksServicesTests &&
+ * adb install \
+ * -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ * adb shell am instrument -e class com.android.server.pm.UserDataPreparerTest \
+ * -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+@SmallTest
+public class UserDataPreparerTest {
+
+    private static final int TEST_USER_SERIAL = 1000;
+    private static final int TEST_USER_ID = 10;
+
+    private TestUserDataPreparer mUserDataPreparer;
+
+    @Mock
+    private StorageManager mStorageManagerMock;
+
+    @Mock
+    private Context mContextMock;
+
+    @Mock
+    private Installer mInstaller;
+
+    private Object mInstallLock;
+
+    @Before
+    public void setup() {
+        Context ctx = InstrumentationRegistry.getContext();
+        FileUtils.deleteContents(ctx.getCacheDir());
+        mInstallLock = new Object();
+        MockitoAnnotations.initMocks(this);
+        mUserDataPreparer = new TestUserDataPreparer(mInstaller, mInstallLock, mContextMock, false,
+                ctx.getCacheDir());
+        when(mContextMock.getSystemServiceName(StorageManager.class))
+                .thenReturn(Context.STORAGE_SERVICE);
+        when(mContextMock.getSystemService(eq(Context.STORAGE_SERVICE)))
+                .thenReturn(mStorageManagerMock);
+        VolumeInfo testVolume = new VolumeInfo("testuuid", VolumeInfo.TYPE_PRIVATE, null, null);
+        when(mStorageManagerMock.getWritablePrivateVolumes()).thenReturn(Arrays.asList(testVolume));
+    }
+
+    @Test
+    public void testPrepareUserData_De() throws Exception {
+        File userDeDir = mUserDataPreparer.getDataUserDeDirectory(null, TEST_USER_ID);
+        userDeDir.mkdirs();
+        File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
+        systemDeDir.mkdirs();
+        mUserDataPreparer
+                .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_DE);
+        verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+                eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
+        verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
+                eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
+        int serialNumber = UserDataPreparer.getSerialNumber(userDeDir);
+        assertEquals(TEST_USER_SERIAL, serialNumber);
+        serialNumber = UserDataPreparer.getSerialNumber(systemDeDir);
+        assertEquals(TEST_USER_SERIAL, serialNumber);
+    }
+
+    @Test
+    public void testPrepareUserData_Ce() throws Exception {
+        File userCeDir = mUserDataPreparer.getDataUserCeDirectory(null, TEST_USER_ID);
+        userCeDir.mkdirs();
+        File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
+        systemCeDir.mkdirs();
+        mUserDataPreparer
+                .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_CE);
+        verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+                eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
+        verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
+                eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
+        int serialNumber = UserDataPreparer.getSerialNumber(userCeDir);
+        assertEquals(TEST_USER_SERIAL, serialNumber);
+        serialNumber = UserDataPreparer.getSerialNumber(systemCeDir);
+        assertEquals(TEST_USER_SERIAL, serialNumber);
+    }
+
+    @Test
+    public void testDestroyUserData() throws Exception {
+        // Add file in CE
+        File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
+        systemCeDir.mkdirs();
+        File ceFile = new File(systemCeDir, "file");
+        writeFile(ceFile, "-----" );
+        testDestroyUserData_De();
+        // CE directory should be preserved
+        assertEquals(Collections.singletonList(ceFile), Arrays.asList(FileUtils.listFilesOrEmpty(
+                systemCeDir)));
+
+        testDestroyUserData_Ce();
+
+        // Verify that testDir is empty
+        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+                mUserDataPreparer.testDir)));
+    }
+
+    @Test
+    public void testDestroyUserData_De() throws Exception {
+        File systemDir = mUserDataPreparer.getUserSystemDirectory(TEST_USER_ID);
+        systemDir.mkdirs();
+        writeFile(new File(systemDir, "file"), "-----" );
+        File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
+        systemDeDir.mkdirs();
+        writeFile(new File(systemDeDir, "file"), "-----" );
+        File miscDeDir = mUserDataPreparer.getDataMiscDeDirectory(TEST_USER_ID);
+        miscDeDir.mkdirs();
+        writeFile(new File(miscDeDir, "file"), "-----" );
+
+        mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
+
+        verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
+                        eq(StorageManager.FLAG_STORAGE_DE));
+        verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
+                        eq(StorageManager.FLAG_STORAGE_DE));
+
+        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(systemDir)));
+        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+                systemDeDir)));
+        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+                miscDeDir)));
+    }
+
+    @Test
+    public void testDestroyUserData_Ce() throws Exception {
+        File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
+        systemCeDir.mkdirs();
+        writeFile(new File(systemCeDir, "file"), "-----" );
+        File miscCeDir = mUserDataPreparer.getDataMiscCeDirectory(TEST_USER_ID);
+        miscCeDir.mkdirs();
+        writeFile(new File(miscCeDir, "file"), "-----" );
+
+        mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_CE);
+
+        verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
+                eq(StorageManager.FLAG_STORAGE_CE));
+        verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
+                eq(StorageManager.FLAG_STORAGE_CE));
+
+        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+                systemCeDir)));
+        assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
+                miscCeDir)));
+    }
+
+    @Test
+    public void testReconcileUsers() throws Exception {
+        UserInfo u1 = new UserInfo(1, "u1", 0);
+        UserInfo u2 = new UserInfo(2, "u2", 0);
+        File testDir = mUserDataPreparer.testDir;
+        File dir1 = new File(testDir, "1");
+        dir1.mkdirs();
+        File dir2 = new File(testDir, "2");
+        dir2.mkdirs();
+        File dir3 = new File(testDir, "3");
+        dir3.mkdirs();
+
+        mUserDataPreparer
+                .reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL, Arrays.asList(u1, u2),
+                        Arrays.asList(dir1, dir2, dir3));
+        // Verify that user 3 data is removed
+        verify(mInstaller).destroyUserData(isNull(String.class), eq(3),
+                eq(StorageManager.FLAG_STORAGE_DE|StorageManager.FLAG_STORAGE_CE));
+    }
+
+    private static void writeFile(File file, String content) throws IOException {
+        try (FileOutputStream os = new FileOutputStream(file)) {
+            os.write(content.getBytes(Charset.defaultCharset()));
+        }
+    }
+
+    private static class TestUserDataPreparer extends UserDataPreparer {
+        File testDir;
+
+        TestUserDataPreparer(Installer installer, Object installLock, Context context,
+                boolean onlyCore, File testDir) {
+            super(installer, installLock, context, onlyCore);
+            this.testDir = testDir;
+        }
+
+        @Override
+        protected File getDataMiscCeDirectory(int userId) {
+            return new File(testDir, "misc_ce_" + userId);
+        }
+
+        @Override
+        protected File getDataSystemCeDirectory(int userId) {
+            return new File(testDir, "system_ce_" + userId);
+        }
+
+        @Override
+        protected File getDataMiscDeDirectory(int userId) {
+            return new File(testDir, "misc_de_" + userId);
+        }
+
+        @Override
+        protected File getUserSystemDirectory(int userId) {
+            return new File(testDir, "user_system_" + userId);
+        }
+
+        @Override
+        protected File getDataUserCeDirectory(String volumeUuid, int userId) {
+            return new File(testDir, "user_ce_" + userId);
+        }
+
+        @Override
+        protected File getDataSystemDeDirectory(int userId) {
+            return new File(testDir, "system_de_" + userId);
+        }
+
+        @Override
+        protected File getDataUserDeDirectory(String volumeUuid, int userId) {
+            return new File(testDir, "user_de_" + userId);
+        }
+
+        @Override
+        protected boolean isFileEncryptedEmulatedOnly() {
+            return false;
+        }
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 154fa91..e15d40e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import org.junit.Test;
+import org.junit.Ignore;
 import org.junit.runner.RunWith;
 
 import android.platform.test.annotations.Presubmit;
@@ -70,6 +71,7 @@
 
         // The base application window should be below all other windows.
         assertEquals(baseWin, token.getFirstChild());
+        token.removeImmediately();
     }
 
     @Test
@@ -86,6 +88,7 @@
         assertEquals(window1, token.findMainWindow());
         final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
         assertEquals(window2, token.findMainWindow());
+        token.removeImmediately();
     }
 
     @Test
@@ -123,6 +126,8 @@
     }
 
     @Test
+    @Ignore
+    // TODO(b/35034729): Need to fix before re-enabling
     public void testLandscapeSeascapeRotationByPolicy() throws Exception {
         // Some plumbing to get the service ready for rotation updates.
         sWm.mDisplayReady = true;
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
index 1260a53..e6975e7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -77,6 +78,7 @@
      * as does some basic tests (e.g. dragging in Y only will keep X stable).
      */
     @Test
+    @Ignore
     public void testBasicFreeWindowResizing() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
@@ -137,6 +139,7 @@
      * This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored.
      */
     @Test
+    @Ignore
     public void testFreeWindowResizingTestAllEdges() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
@@ -221,6 +224,7 @@
      * right things upon resizing when dragged from the top left corner.
      */
     @Test
+    @Ignore
     public void testLandscapePreservedWindowResizingDragTopLeft() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
 
@@ -258,6 +262,7 @@
      * right things upon resizing when dragged from the left corner.
      */
     @Test
+    @Ignore
     public void testLandscapePreservedWindowResizingDragLeft() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
@@ -298,6 +303,7 @@
      * right things upon resizing when dragged from the top corner.
      */
     @Test
+    @Ignore
     public void testLandscapePreservedWindowResizingDragTop() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
@@ -334,6 +340,7 @@
      * right things upon resizing when dragged from the top left corner.
      */
     @Test
+    @Ignore
     public void testPortraitPreservedWindowResizingDragTopLeft() throws Exception {
         final Rect r = new Rect(330, 100, 630, 600);
 
@@ -366,6 +373,7 @@
      * right things upon resizing when dragged from the left corner.
      */
     @Test
+    @Ignore
     public void testPortraitPreservedWindowResizingDragLeft() throws Exception {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midY = (r.top + r.bottom) / 2;
@@ -408,6 +416,7 @@
      * right things upon resizing when dragged from the top corner.
      */
     @Test
+    @Ignore
     public void testPortraitPreservedWindowResizingDragTop() throws Exception {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midX = (r.left + r.right) / 2;
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 1e471e3..dd45d9b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -18,8 +18,12 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
+import org.mockito.invocation.InvocationOnMock;
 
 import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -64,6 +68,19 @@
                 LocalServices.addService(PowerManagerInternal.class,
                         mock(PowerManagerInternal.class));
             }
+            if (LocalServices.getService(ActivityManagerInternal.class) == null) {
+                LocalServices.addService(ActivityManagerInternal.class,
+                        mock(ActivityManagerInternal.class));
+                final ActivityManagerInternal am =
+                        LocalServices.getService(ActivityManagerInternal.class);
+                doAnswer((InvocationOnMock invocationOnMock) -> {
+                    final Runnable runnable = invocationOnMock.getArgumentAt(0, Runnable.class);
+                    if (runnable != null) {
+                        runnable.run();
+                    }
+                    return null;
+                }).when(am).notifyKeyguardFlagsChanged(any());
+            }
             sWm = WindowManagerService.main(context, mock(InputManagerService.class), true, false,
                     false, new TestWindowManagerPolicy());
         }
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 772bfb4..cf8af67 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -17,25 +17,14 @@
 package com.android.server.wm;
 
 import static junit.framework.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doAnswer;
 
-import android.app.ActivityManagerInternal;
-import android.content.Context;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.android.server.LocalServices;
-
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
 
 /**
  * Test class for {@link AppTransition}.
@@ -52,64 +41,50 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        final Context context = InstrumentationRegistry.getTargetContext();
-        doAnswer((InvocationOnMock invocationOnMock) -> {
-            invocationOnMock.getArgumentAt(0, Runnable.class).run();
-            return null;
-        }).when(sMockAm).notifyKeyguardFlagsChanged(any());
-        mWm = TestWindowManagerPolicy.getWindowManagerService(context);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        sWm.mUnknownAppVisibilityController.clear();
     }
 
     @Test
     public void testFlow() throws Exception {
-        AppWindowToken token = createAppToken();
-        mWm.mUnknownAppVisibilityController.notifyLaunched(token);
-        mWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
-        mWm.mUnknownAppVisibilityController.notifyRelayouted(token);
+        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        sWm.mUnknownAppVisibilityController.notifyLaunched(token);
+        sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
+        sWm.mUnknownAppVisibilityController.notifyRelayouted(token);
 
         // Make sure our handler processed the message.
         Thread.sleep(100);
-        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
+        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
     public void testMultiple() throws Exception {
-        AppWindowToken token1 = createAppToken();
-        AppWindowToken token2 = createAppToken();
-        mWm.mUnknownAppVisibilityController.notifyLaunched(token1);
-        mWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
-        mWm.mUnknownAppVisibilityController.notifyLaunched(token2);
-        mWm.mUnknownAppVisibilityController.notifyRelayouted(token1);
-        mWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token2);
-        mWm.mUnknownAppVisibilityController.notifyRelayouted(token2);
+        final AppWindowToken token1 = new TestAppWindowToken(sDisplayContent);
+        final AppWindowToken token2 = new TestAppWindowToken(sDisplayContent);
+        sWm.mUnknownAppVisibilityController.notifyLaunched(token1);
+        sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
+        sWm.mUnknownAppVisibilityController.notifyLaunched(token2);
+        sWm.mUnknownAppVisibilityController.notifyRelayouted(token1);
+        sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token2);
+        sWm.mUnknownAppVisibilityController.notifyRelayouted(token2);
 
         // Make sure our handler processed the message.
         Thread.sleep(100);
-        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
+        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
     public void testClear() throws Exception {
-        AppWindowToken token = createAppToken();
-        mWm.mUnknownAppVisibilityController.notifyLaunched(token);
-        mWm.mUnknownAppVisibilityController.clear();;
-        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
+        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        sWm.mUnknownAppVisibilityController.notifyLaunched(token);
+        sWm.mUnknownAppVisibilityController.clear();;
+        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
     public void testAppRemoved() throws Exception {
-        AppWindowToken token = createAppToken();
-        mWm.mUnknownAppVisibilityController.notifyLaunched(token);
-        mWm.mUnknownAppVisibilityController.appRemoved(token);
-        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
-    }
-
-    private AppWindowToken createAppToken() {
-        return new AppWindowToken(mWm, null, false, mWm.getDefaultDisplayContentLocked());
+        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        sWm.mUnknownAppVisibilityController.notifyLaunched(token);
+        sWm.mUnknownAppVisibilityController.appRemoved(token);
+        assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 4f9cd95..74557e2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -392,7 +392,7 @@
         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
             SCREEN_ORIENTATION_LANDSCAPE);
         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
-            SCREEN_ORIENTATION_UNSET);
+            SCREEN_ORIENTATION_UNSPECIFIED);
     }
 
     private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 4cad4e8..98ff0e2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -78,8 +78,7 @@
         final Rect mInsetBounds = new Rect();
         boolean mFullscreenForTest = true;
         TaskWithBounds(Rect bounds) {
-            super(0, mStubStack, 0, sWm, null, null, false, 0, false, false, new TaskDescription(),
-                    null);
+            super(0, mStubStack, 0, sWm, null, null, 0, false, false, new TaskDescription(), null);
             mBounds = bounds;
         }
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
index c8650bf..b99b8fe 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
@@ -135,8 +135,9 @@
 
     @Test
     public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
-        final WindowState imeSystemOverlayTarget =
-                createWindow(null, TYPE_SYSTEM_OVERLAY, sDisplayContent, "imeSystemOverlayTarget");
+        final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
+                sDisplayContent, "imeSystemOverlayTarget",
+                true /* ownerCanAddInternalSystemWindow */);
 
         sWm.mInputMethodTarget = imeSystemOverlayTarget;
         sLayersController.assignWindowLayers(sDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 7dec52d..8a94b83 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityManagerInternal;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
@@ -26,9 +25,8 @@
 import android.view.DisplayInfo;
 import android.view.IApplicationToken;
 import org.junit.Assert;
+import org.junit.After;
 import org.junit.Before;
-import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import android.app.ActivityManager.TaskSnapshot;
@@ -59,7 +57,8 @@
 import static org.mockito.Mockito.mock;
 
 import com.android.server.AttributeCache;
-import com.android.server.LocalServices;
+
+import java.util.HashSet;
 
 /**
  * Common base class for window manager unit test classes.
@@ -86,18 +85,16 @@
     static WindowState sAppWindow;
     static WindowState sChildAppWindowAbove;
     static WindowState sChildAppWindowBelow;
-    static @Mock ActivityManagerInternal sMockAm;
+    static HashSet<WindowState> sCommonWindows;
 
     @Before
     public void setUp() throws Exception {
         if (sOneTimeSetupDone) {
-            Mockito.reset(sMockAm);
             return;
         }
         sOneTimeSetupDone = true;
         MockitoAnnotations.initMocks(this);
         final Context context = InstrumentationRegistry.getTargetContext();
-        LocalServices.addService(ActivityManagerInternal.class, sMockAm);
         AttributeCache.init(context);
         sWm = TestWindowManagerPolicy.getWindowManagerService(context);
         sPolicy = (TestWindowManagerPolicy) sWm.mPolicy;
@@ -119,20 +116,33 @@
         sWm.mDisplayReady = true;
 
         // Set-up some common windows.
-        sWallpaperWindow = createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
-        sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow");
-        sImeDialogWindow =
-                createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow");
-        sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow");
-        sNavBarWindow =
-                createWindow(null, TYPE_NAVIGATION_BAR, sDisplayContent, "sNavBarWindow");
-        sDockedDividerWindow =
-                createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
-        sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
-        sChildAppWindowAbove = createWindow(sAppWindow,
-                TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindowAbove");
-        sChildAppWindowBelow = createWindow(sAppWindow,
-                TYPE_APPLICATION_MEDIA_OVERLAY, sAppWindow.mToken, "sChildAppWindowBelow");
+        sCommonWindows = new HashSet();
+        sWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
+        sImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "sImeWindow");
+        sImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG, "sImeDialogWindow");
+        sStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "sStatusBarWindow");
+        sNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "sNavBarWindow");
+        sDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER, "sDockedDividerWindow");
+        sAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "sAppWindow");
+        sChildAppWindowAbove = createCommonWindow(sAppWindow, TYPE_APPLICATION_ATTACHED_DIALOG,
+                "sChildAppWindowAbove");
+        sChildAppWindowBelow = createCommonWindow(sAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
+                "sChildAppWindowBelow");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        sWm.mRoot.forAllWindows(w -> {
+            if (!sCommonWindows.contains(w)) {
+                w.removeImmediately();
+            }
+        }, true /* traverseTopToBottom */);
+    }
+
+    private static WindowState createCommonWindow(WindowState parent, int type, String name) {
+        final WindowState win = createWindow(parent, type, name);
+        sCommonWindows.add(win);
+        return win;
     }
 
     /** Asserts that the first entry is greater than the second entry. */
@@ -176,12 +186,23 @@
         return createWindow(parent, type, token, name);
     }
 
+    static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
+            boolean ownerCanAddInternalSystemWindow) {
+        final WindowToken token = createWindowToken(dc, type);
+        return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow);
+    }
+
     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
+        return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */);
+    }
+
+    static WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
+            boolean ownerCanAddInternalSystemWindow) {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
         attrs.setTitle(name);
 
         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
-                0, attrs, 0, 0, false /* ownerCanAddInternalSystemWindow */);
+                0, attrs, 0, 0, ownerCanAddInternalSystemWindow);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
         token.addWindow(w);
@@ -201,8 +222,8 @@
 
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     static Task createTaskInStack(TaskStack stack, int userId) {
-        final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, false, 0,
-                false, false, new TaskDescription(), null);
+        final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, 0, false,
+                false, new TaskDescription(), null);
         stack.addTask(newTask, POSITION_TOP);
         return newTask;
     }
@@ -240,7 +261,7 @@
     static class TestAppWindowToken extends AppWindowToken {
 
         TestAppWindowToken(DisplayContent dc) {
-            super(sWm, null, false, dc);
+            super(sWm, null, false, dc, true /* fillsParent */);
         }
 
         TestAppWindowToken(WindowManagerService service, IApplicationToken token,
@@ -283,12 +304,10 @@
         private boolean mIsAnimating = false;
 
         TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-                Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
-                boolean supportsPictureInPicture, boolean homeTask,
-                TaskWindowContainerController controller) {
-            super(taskId, stack, userId, service, bounds, overrideConfig, isOnTopLauncher,
-                    resizeMode, supportsPictureInPicture, homeTask, new TaskDescription(),
-                            controller);
+                Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+                boolean homeTask, TaskWindowContainerController controller) {
+            super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
+                    supportsPictureInPicture, homeTask, new TaskDescription(), controller);
         }
 
         boolean shouldDeferRemoval() {
@@ -339,17 +358,16 @@
                         }
                     }, stackController, 0 /* userId */, null /* bounds */,
                     EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
-                    false /* supportsPictureInPicture */, false /* homeTask*/,
-                    false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */,
-                    new TaskDescription(), sWm);
+                    false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
+                    true /* showForAllUsers */, new TaskDescription(), sWm);
         }
 
         @Override
         TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
                 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
-                boolean homeTask, boolean isOnTopLauncher, TaskDescription taskDescription) {
-            return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig,
-                    isOnTopLauncher, resizeMode, supportsPictureInPicture, homeTask, this);
+                boolean homeTask, TaskDescription taskDescription) {
+            return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
+                    supportsPictureInPicture, homeTask, this);
         }
     }
 
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index d0ccd55..6e10029 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -98,6 +98,7 @@
     private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA";
     private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA";
     private static final String SESSION_CREATE_CONN = "CS.crCo";
+    private static final String SESSION_CREATE_CONN_FAILED = "CS.crCoF";
     private static final String SESSION_ABORT = "CS.ab";
     private static final String SESSION_ANSWER = "CS.an";
     private static final String SESSION_ANSWER_VIDEO = "CS.anV";
@@ -142,6 +143,7 @@
     private static final int MSG_PULL_EXTERNAL_CALL = 22;
     private static final int MSG_SEND_CALL_EVENT = 23;
     private static final int MSG_ON_EXTRAS_CHANGED = 24;
+    private static final int MSG_CREATE_CONNECTION_FAILED = 25;
 
     private static Connection sNullConnection;
 
@@ -211,6 +213,25 @@
         }
 
         @Override
+        public void createConnectionFailed(
+                String callId,
+                ConnectionRequest request,
+                boolean isIncoming,
+                Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_CREATE_CONN_FAILED);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = request;
+                args.arg3 = Log.createSubsession();
+                args.argi1 = isIncoming ? 1 : 0;
+                mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void abort(String callId, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_ABORT);
             try {
@@ -552,6 +573,35 @@
                     }
                     break;
                 }
+                case MSG_CREATE_CONNECTION_FAILED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg3, SESSION_HANDLER +
+                            SESSION_CREATE_CONN_FAILED);
+                    try {
+                        final String id = (String) args.arg1;
+                        final ConnectionRequest request = (ConnectionRequest) args.arg2;
+                        final boolean isIncoming = args.argi1 == 1;
+                        if (!mAreAccountsInitialized) {
+                            Log.d(this, "Enqueueing pre-init request %s", id);
+                            mPreInitializationConnectionRequests.add(
+                                    new android.telecom.Logging.Runnable(
+                                            SESSION_HANDLER + SESSION_CREATE_CONN_FAILED + ".pICR",
+                                            null /*lock*/) {
+                                        @Override
+                                        public void loggedRun() {
+                                            createConnectionFailed(id, request, isIncoming);
+                                        }
+                                    }.prepare());
+                        } else {
+                            Log.i(this, "createConnectionFailed %s", id);
+                            createConnectionFailed(id, request, isIncoming);
+                        }
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_ABORT: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
@@ -1175,6 +1225,17 @@
         }
     }
 
+    private void createConnectionFailed(final String callId, final ConnectionRequest request,
+            boolean isIncoming) {
+
+        Log.i(this, "createConnectionFailed %s", callId);
+        if (isIncoming) {
+            onCreateIncomingConnectionFailed(request);
+        } else {
+            onCreateOutgoingConnectionFailed(request);
+        }
+    }
+
     private void abort(String callId) {
         Log.d(this, "abort %s", callId);
         findConnectionForAction(callId, "abort").onAbort();
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ba7b6a1..96070b8 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1517,6 +1517,10 @@
      *      otherwise.
      */
     public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+        if (phoneAccountHandle == null) {
+            return false;
+        }
+
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 8a27675..20feba7 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -46,6 +46,9 @@
             boolean isUnknown,
             in Session.Info sessionInfo);
 
+    void createConnectionFailed(String callId, in ConnectionRequest request, boolean isIncoming,
+            in Session.Info sessionInfo);
+
     void abort(String callId, in Session.Info sessionInfo);
 
     void answerVideo(String callId, int videoState, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 6ca0bc5..d9465dc 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -259,4 +259,9 @@
      * @see TelecomServiceImpl#isOutgoingCallPermitted
      */
     boolean isOutgoingCallPermitted(in PhoneAccountHandle phoneAccountHandle);
+
+    /**
+     * @see TelecomServiceImpl#waitOnHandler
+     */
+    void waitOnHandlers();
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 891b8a1a..5ee7e23 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -417,7 +417,7 @@
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
-    int RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002;
+    int RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED = 1002;
     int RIL_UNSOL_RESPONSE_NEW_SMS = 1003;
     int RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
     int RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM = 1005;
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
index 6629770..251bf24 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
@@ -30,8 +30,9 @@
 import android.transition.AutoTransition;
 import android.transition.ChangeBounds;
 import android.transition.Transition;
-import android.transition.TransitionSet;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
+import android.transition.TransitionSet;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -84,7 +85,7 @@
         fadeIn.setDuration(50);
         noFadeIn.addTransition(new Fade(Fade.OUT)).addTransition(new ChangeBounds()).addTransition(fadeIn);
 
-        myTransition.addListener(new Transition.TransitionListenerAdapter() {
+        myTransition.addListener(new TransitionListenerAdapter() {
             @Override
             public void onTransitionStart(Transition transition) {
                 System.out.println("---------ListView Tops: Before--------");
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 5767f11..0401737 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -172,12 +172,10 @@
     @Override
     public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
         mAssistStructure = structure;
-        if (mAssistStructure != null) {
-            if (mAssistVisualizer != null) {
+        if (mAssistVisualizer != null) {
+            if (mAssistStructure != null) {
                 mAssistVisualizer.setAssistStructure(mAssistStructure);
-            }
-        } else {
-            if (mAssistVisualizer != null) {
+            } else {
                 mAssistVisualizer.clearAssistData();
             }
         }
@@ -207,19 +205,24 @@
 
     @Override
     public void onHandleScreenshot(Bitmap screenshot) {
-        if (screenshot != null) {
-            mScreenshot.setImageBitmap(screenshot);
-            mScreenshot.setAdjustViewBounds(true);
-            mScreenshot.setMaxWidth(screenshot.getWidth() / 3);
-            mScreenshot.setMaxHeight(screenshot.getHeight() / 3);
-            mFullScreenshot.setImageBitmap(screenshot);
-        } else {
-            mScreenshot.setImageDrawable(null);
-            mFullScreenshot.setImageDrawable(null);
+        if (mScreenshot != null) {
+            if (screenshot != null) {
+                mScreenshot.setImageBitmap(screenshot);
+                mScreenshot.setAdjustViewBounds(true);
+                mScreenshot.setMaxWidth(screenshot.getWidth() / 3);
+                mScreenshot.setMaxHeight(screenshot.getHeight() / 3);
+                mFullScreenshot.setImageBitmap(screenshot);
+            } else {
+                mScreenshot.setImageDrawable(null);
+                mFullScreenshot.setImageDrawable(null);
+            }
         }
     }
 
     void updateState() {
+        if (mTopContent == null) {
+            return;
+        }
         if (mState == STATE_IDLE) {
             mTopContent.setVisibility(View.VISIBLE);
             mBottomContent.setVisibility(View.GONE);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 63498f7..ff306ce 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2204,8 +2204,10 @@
                            package.string(), package.size(),
                            &specFlags);
     if (rid != 0) {
-        if (onlyPublic) {
-            if ((specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
+        if (onlyPublic && (specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
+            // If this is a feature split and the resource has the same
+            // package name as us, then everything is public.
+            if (mPackageType != AppFeature || mAssetsPackage != package) {
                 return 0;
             }
         }
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 76792ce..3d7bd94 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -86,8 +86,7 @@
     if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
       if (context->IsVerbose()) {
         context->GetDiagnostics()->Note(DiagMessage()
-                                        << "Resource '" << path << "' not referenced in "
-                                        << "resource table; removing from APK.");
+                                        << "Removing resource '" << path << "' from APK.");
       }
       continue;
     }
@@ -110,8 +109,8 @@
     }
 
     std::unique_ptr<io::IData> data = file->OpenAsData();
-    // TODO(lecesne): Only compress the files that were compressed in the original APK.
-    if (!writer->StartEntry(path, ArchiveEntry::kCompress) ||
+    uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
+    if (!writer->StartEntry(path, compression_flags) ||
         !writer->WriteEntry(data->data(), data->size()) || !writer->FinishEntry()) {
       context->GetDiagnostics()->Error(DiagMessage()
                                        << "Error when writing file '" << path << "' in APK.");
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 3ed698b..ba378d7 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,7 +25,7 @@
 static const char* sMajorVersion = "2";
 
 // Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "5";
+static const char* sMinorVersion = "7";
 
 int PrintVersion() {
   std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index fdabce1..35971e7 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -39,6 +39,8 @@
       return "bool";
     case ResourceType::kColor:
       return "color";
+    case ResourceType::kConfigVarying:
+      return "configVarying";
     case ResourceType::kDimen:
       return "dimen";
     case ResourceType::kDrawable:
@@ -85,6 +87,7 @@
     {"^attr-private", ResourceType::kAttrPrivate},
     {"bool", ResourceType::kBool},
     {"color", ResourceType::kColor},
+    {"configVarying", ResourceType::kConfigVarying},
     {"dimen", ResourceType::kDimen},
     {"drawable", ResourceType::kDrawable},
     {"font", ResourceType::kFont},
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 1950ea3..4d915d9 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -44,6 +44,11 @@
   kAttrPrivate,
   kBool,
   kColor,
+
+  // Not really a type, but it shows up in some CTS tests and
+  // we need to continue respecting it.
+  kConfigVarying,
+
   kDimen,
   kDrawable,
   kFont,
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 79379fe..47ca266 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -26,6 +26,7 @@
 #include "ResourceValues.h"
 #include "ValueVisitor.h"
 #include "util/ImmutableMap.h"
+#include "util/Maybe.h"
 #include "util/Util.h"
 #include "xml/XmlPullParser.h"
 
@@ -150,82 +151,108 @@
 /**
  * Build a string from XML that converts nested elements into Span objects.
  */
-bool ResourceParser::FlattenXmlSubtree(xml::XmlPullParser* parser,
-                                       std::string* out_raw_string,
-                                       StyleString* out_style_string) {
+bool ResourceParser::FlattenXmlSubtree(
+    xml::XmlPullParser* parser, std::string* out_raw_string, StyleString* out_style_string,
+    std::vector<UntranslatableSection>* out_untranslatable_sections) {
+  // Keeps track of formatting tags (<b>, <i>) and the range of characters for which they apply.
   std::vector<Span> span_stack;
 
-  bool error = false;
+  // Clear the output variables.
   out_raw_string->clear();
   out_style_string->spans.clear();
+  out_untranslatable_sections->clear();
+
+  // The StringBuilder will concatenate the various segments of text which are initially
+  // separated by tags. It also handles unicode escape codes and quotations.
   util::StringBuilder builder;
+
+  // The first occurrence of a <xliff:g> tag. Nested <xliff:g> tags are illegal.
+  Maybe<size_t> untranslatable_start_depth;
+
   size_t depth = 1;
   while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
     const xml::XmlPullParser::Event event = parser->event();
-    if (event == xml::XmlPullParser::Event::kEndElement) {
-      if (!parser->element_namespace().empty()) {
-        // We already warned and skipped the start element, so just skip here
-        // too
-        continue;
+
+    if (event == xml::XmlPullParser::Event::kStartElement) {
+      if (parser->element_namespace().empty()) {
+        // This is an HTML tag which we encode as a span. Add it to the span stack.
+        std::string span_name = parser->element_name();
+        const auto end_attr_iter = parser->end_attributes();
+        for (auto attr_iter = parser->begin_attributes(); attr_iter != end_attr_iter; ++attr_iter) {
+          span_name += ";";
+          span_name += attr_iter->name;
+          span_name += "=";
+          span_name += attr_iter->value;
+        }
+
+        // Make sure the string is representable in our binary format.
+        if (builder.Utf16Len() > std::numeric_limits<uint32_t>::max()) {
+          diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+                       << "style string '" << builder.ToString() << "' is too long");
+          return false;
+        }
+
+        span_stack.push_back(Span{std::move(span_name), static_cast<uint32_t>(builder.Utf16Len())});
+      } else if (parser->element_namespace() == sXliffNamespaceUri) {
+        if (parser->element_name() == "g") {
+          if (untranslatable_start_depth) {
+            // We've already encountered an <xliff:g> tag, and nested <xliff:g> tags are illegal.
+            diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+                         << "illegal nested XLIFF 'g' tag");
+            return false;
+          } else {
+            // Mark the start of an untranslatable section. Use UTF8 indices/lengths.
+            untranslatable_start_depth = depth;
+            const size_t current_idx = builder.ToString().size();
+            out_untranslatable_sections->push_back(UntranslatableSection{current_idx, current_idx});
+          }
+        }
+        // Ignore other xliff tags, they get handled by other tools.
+
+      } else {
+        // Besides XLIFF, any other namespaced tag is unsupported and ignored.
+        diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
+                    << "ignoring element '" << parser->element_name()
+                    << "' with unknown namespace '" << parser->element_namespace() << "'");
       }
 
+      // Enter one level inside the element.
+      depth++;
+    } else if (event == xml::XmlPullParser::Event::kText) {
+      // Record both the raw text and append to the builder to deal with escape sequences
+      // and quotations.
+      out_raw_string->append(parser->text());
+      builder.Append(parser->text());
+    } else if (event == xml::XmlPullParser::Event::kEndElement) {
+      // Return one level from within the element.
       depth--;
       if (depth == 0) {
         break;
       }
 
-      span_stack.back().last_char = builder.Utf16Len() - 1;
-      out_style_string->spans.push_back(span_stack.back());
-      span_stack.pop_back();
-
-    } else if (event == xml::XmlPullParser::Event::kText) {
-      out_raw_string->append(parser->text());
-      builder.Append(parser->text());
-
-    } else if (event == xml::XmlPullParser::Event::kStartElement) {
-      if (!parser->element_namespace().empty()) {
-        if (parser->element_namespace() != sXliffNamespaceUri) {
-          // Only warn if this isn't an xliff namespace.
-          diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
-                      << "skipping element '" << parser->element_name()
-                      << "' with unknown namespace '"
-                      << parser->element_namespace() << "'");
-        }
-        continue;
+      if (parser->element_namespace().empty()) {
+        // This is an HTML tag which we encode as a span. Update the span
+        // stack and pop the top entry.
+        Span& top_span = span_stack.back();
+        top_span.last_char = builder.Utf16Len() - 1;
+        out_style_string->spans.push_back(std::move(top_span));
+        span_stack.pop_back();
+      } else if (untranslatable_start_depth == make_value(depth)) {
+        // This is the end of an untranslatable section. Use UTF8 indices/lengths.
+        UntranslatableSection& untranslatable_section = out_untranslatable_sections->back();
+        untranslatable_section.end = builder.ToString().size();
+        untranslatable_start_depth = {};
       }
-      depth++;
-
-      // Build a span object out of the nested element.
-      std::string span_name = parser->element_name();
-      const auto end_attr_iter = parser->end_attributes();
-      for (auto attr_iter = parser->begin_attributes();
-           attr_iter != end_attr_iter; ++attr_iter) {
-        span_name += ";";
-        span_name += attr_iter->name;
-        span_name += "=";
-        span_name += attr_iter->value;
-      }
-
-      if (builder.Utf16Len() > std::numeric_limits<uint32_t>::max()) {
-        diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
-                     << "style string '" << builder.ToString()
-                     << "' is too long");
-        error = true;
-      } else {
-        span_stack.push_back(
-            Span{span_name, static_cast<uint32_t>(builder.Utf16Len())});
-      }
-
     } else if (event == xml::XmlPullParser::Event::kComment) {
-      // Skip
+      // Ignore.
     } else {
       LOG(FATAL) << "unhandled XML event";
     }
   }
-  CHECK(span_stack.empty()) << "spans haven't been fully processed";
 
+  CHECK(span_stack.empty()) << "spans haven't been fully processed";
   out_style_string->str = builder.ToString();
-  return !error;
+  return true;
 }
 
 bool ResourceParser::Parse(xml::XmlPullParser* parser) {
@@ -338,50 +365,52 @@
   using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*,
                                           ParsedResource*)>;
 
-  static const auto elToItemMap =
-      ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
-          {"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
-          {"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
-          {"dimen",
-           {ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT |
-                                      android::ResTable_map::TYPE_FRACTION |
-                                      android::ResTable_map::TYPE_DIMENSION}},
-          {"drawable",
-           {ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
-          {"fraction",
-           {ResourceType::kFraction,
-            android::ResTable_map::TYPE_FLOAT |
-                android::ResTable_map::TYPE_FRACTION |
-                android::ResTable_map::TYPE_DIMENSION}},
-          {"integer",
-           {ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
-          {"string",
-           {ResourceType::kString, android::ResTable_map::TYPE_STRING}},
-      });
+  static const auto elToItemMap = ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
+      {"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
+      {"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
+      {"configVarying", {ResourceType::kConfigVarying, android::ResTable_map::TYPE_ANY}},
+      {"dimen",
+       {ResourceType::kDimen,
+        android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
+            android::ResTable_map::TYPE_DIMENSION}},
+      {"drawable", {ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
+      {"fraction",
+       {ResourceType::kFraction,
+        android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
+            android::ResTable_map::TYPE_DIMENSION}},
+      {"integer", {ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
+      {"string", {ResourceType::kString, android::ResTable_map::TYPE_STRING}},
+  });
 
-  static const auto elToBagMap =
-      ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
-          {"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
-          {"array", std::mem_fn(&ResourceParser::ParseArray)},
-          {"attr", std::mem_fn(&ResourceParser::ParseAttr)},
-          {"declare-styleable",
-           std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
-          {"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
-          {"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
-          {"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
-          {"public", std::mem_fn(&ResourceParser::ParsePublic)},
-          {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
-          {"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
-          {"style", std::mem_fn(&ResourceParser::ParseStyle)},
-          {"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
-      });
+  static const auto elToBagMap = ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
+      {"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
+      {"array", std::mem_fn(&ResourceParser::ParseArray)},
+      {"attr", std::mem_fn(&ResourceParser::ParseAttr)},
+      {"configVarying",
+       std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kConfigVarying,
+                 std::placeholders::_2, std::placeholders::_3)},
+      {"declare-styleable", std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
+      {"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
+      {"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
+      {"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
+      {"public", std::mem_fn(&ResourceParser::ParsePublic)},
+      {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
+      {"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
+      {"style", std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kStyle,
+                          std::placeholders::_2, std::placeholders::_3)},
+      {"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
+  });
 
   std::string resource_type = parser->element_name();
 
   // The value format accepted for this resource.
   uint32_t resource_format = 0u;
 
+  bool can_be_item = true;
+  bool can_be_bag = true;
   if (resource_type == "item") {
+    can_be_bag = false;
+
     // Items have their type encoded in the type attribute.
     if (Maybe<StringPiece> maybe_type =
             xml::FindNonEmptyAttribute(parser, "type")) {
@@ -406,6 +435,17 @@
         return false;
       }
     }
+  } else if (resource_type == "bag") {
+    can_be_item = false;
+
+    // Bags have their type encoded in the type attribute.
+    if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+      resource_type = maybe_type.value().to_string();
+    } else {
+      diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+                   << "<bag> must have a 'type' attribute");
+      return false;
+    }
   }
 
   // Get the name of the resource. This will be checked later, because not all
@@ -426,36 +466,61 @@
     return true;
   }
 
-  const auto item_iter = elToItemMap.find(resource_type);
-  if (item_iter != elToItemMap.end()) {
-    // This is an item, record its type and format and start parsing.
+  if (can_be_item) {
+    const auto item_iter = elToItemMap.find(resource_type);
+    if (item_iter != elToItemMap.end()) {
+      // This is an item, record its type and format and start parsing.
 
-    if (!maybe_name) {
-      diag_->Error(DiagMessage(out_resource->source)
-                   << "<" << parser->element_name()
-                   << "> missing 'name' attribute");
-      return false;
+      if (!maybe_name) {
+        diag_->Error(DiagMessage(out_resource->source)
+                     << "<" << parser->element_name() << "> missing 'name' attribute");
+        return false;
+      }
+
+      out_resource->name.type = item_iter->second.type;
+      out_resource->name.entry = maybe_name.value().to_string();
+
+      // Only use the implicit format for this type if it wasn't overridden.
+      if (!resource_format) {
+        resource_format = item_iter->second.format;
+      }
+
+      if (!ParseItem(parser, out_resource, resource_format)) {
+        return false;
+      }
+      return true;
     }
-
-    out_resource->name.type = item_iter->second.type;
-    out_resource->name.entry = maybe_name.value().to_string();
-
-    // Only use the implicit format for this type if it wasn't overridden.
-    if (!resource_format) {
-      resource_format = item_iter->second.format;
-    }
-
-    if (!ParseItem(parser, out_resource, resource_format)) {
-      return false;
-    }
-    return true;
   }
 
   // This might be a bag or something.
-  const auto bag_iter = elToBagMap.find(resource_type);
-  if (bag_iter != elToBagMap.end()) {
-    // Ensure we have a name (unless this is a <public-group>).
-    if (resource_type != "public-group") {
+  if (can_be_bag) {
+    const auto bag_iter = elToBagMap.find(resource_type);
+    if (bag_iter != elToBagMap.end()) {
+      // Ensure we have a name (unless this is a <public-group>).
+      if (resource_type != "public-group") {
+        if (!maybe_name) {
+          diag_->Error(DiagMessage(out_resource->source)
+                       << "<" << parser->element_name() << "> missing 'name' attribute");
+          return false;
+        }
+
+        out_resource->name.entry = maybe_name.value().to_string();
+      }
+
+      // Call the associated parse method. The type will be filled in by the
+      // parse func.
+      if (!bag_iter->second(this, parser, out_resource)) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  if (can_be_item) {
+    // Try parsing the elementName (or type) as a resource. These shall only be
+    // resources like 'layout' or 'xml' and they can only be references.
+    const ResourceType* parsed_type = ParseResourceType(resource_type);
+    if (parsed_type) {
       if (!maybe_name) {
         diag_->Error(DiagMessage(out_resource->source)
                      << "<" << parser->element_name()
@@ -463,39 +528,16 @@
         return false;
       }
 
+      out_resource->name.type = *parsed_type;
       out_resource->name.entry = maybe_name.value().to_string();
+      out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
+      if (!out_resource->value) {
+        diag_->Error(DiagMessage(out_resource->source)
+                     << "invalid value for type '" << *parsed_type << "'. Expected a reference");
+        return false;
+      }
+      return true;
     }
-
-    // Call the associated parse method. The type will be filled in by the
-    // parse func.
-    if (!bag_iter->second(this, parser, out_resource)) {
-      return false;
-    }
-    return true;
-  }
-
-  // Try parsing the elementName (or type) as a resource. These shall only be
-  // resources like 'layout' or 'xml' and they can only be references.
-  const ResourceType* parsed_type = ParseResourceType(resource_type);
-  if (parsed_type) {
-    if (!maybe_name) {
-      diag_->Error(DiagMessage(out_resource->source)
-                   << "<" << parser->element_name()
-                   << "> missing 'name' attribute");
-      return false;
-    }
-
-    out_resource->name.type = *parsed_type;
-    out_resource->name.entry = maybe_name.value().to_string();
-    out_resource->value =
-        ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
-    if (!out_resource->value) {
-      diag_->Error(DiagMessage(out_resource->source)
-                   << "invalid value for type '" << *parsed_type
-                   << "'. Expected a reference");
-      return false;
-    }
-    return true;
   }
 
   diag_->Warn(DiagMessage(out_resource->source)
@@ -533,15 +575,18 @@
 
   std::string raw_value;
   StyleString style_string;
-  if (!FlattenXmlSubtree(parser, &raw_value, &style_string)) {
+  std::vector<UntranslatableSection> untranslatable_sections;
+  if (!FlattenXmlSubtree(parser, &raw_value, &style_string, &untranslatable_sections)) {
     return {};
   }
 
   if (!style_string.spans.empty()) {
     // This can only be a StyledString.
-    return util::make_unique<StyledString>(table_->string_pool.MakeRef(
-        style_string,
-        StringPool::Context(StringPool::Context::kStylePriority, config_)));
+    std::unique_ptr<StyledString> styled_string =
+        util::make_unique<StyledString>(table_->string_pool.MakeRef(
+            style_string, StringPool::Context(StringPool::Context::kStylePriority, config_)));
+    styled_string->untranslatable_sections = std::move(untranslatable_sections);
+    return std::move(styled_string);
   }
 
   auto on_create_reference = [&](const ResourceName& name) {
@@ -567,8 +612,10 @@
   // Try making a regular string.
   if (type_mask & android::ResTable_map::TYPE_STRING) {
     // Use the trimmed, escaped string.
-    return util::make_unique<String>(table_->string_pool.MakeRef(
-        style_string.str, StringPool::Context(config_)));
+    std::unique_ptr<String> string = util::make_unique<String>(
+        table_->string_pool.MakeRef(style_string.str, StringPool::Context(config_)));
+    string->untranslatable_sections = std::move(untranslatable_sections);
+    return std::move(string);
   }
 
   if (allow_raw_value) {
@@ -594,17 +641,15 @@
     formatted = maybe_formatted.value();
   }
 
-  bool translateable = options_.translatable;
-  if (Maybe<StringPiece> translateable_attr =
-          xml::FindAttribute(parser, "translatable")) {
-    Maybe<bool> maybe_translateable =
-        ResourceUtils::ParseBool(translateable_attr.value());
-    if (!maybe_translateable) {
+  bool translatable = options_.translatable;
+  if (Maybe<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
+    Maybe<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
+    if (!maybe_translatable) {
       diag_->Error(DiagMessage(out_resource->source)
                    << "invalid value for 'translatable'. Must be a boolean");
       return false;
     }
-    translateable = maybe_translateable.value();
+    translatable = maybe_translatable.value();
   }
 
   out_resource->value =
@@ -615,9 +660,9 @@
   }
 
   if (String* string_value = ValueCast<String>(out_resource->value.get())) {
-    string_value->SetTranslateable(translateable);
+    string_value->SetTranslatable(translatable);
 
-    if (formatted && translateable) {
+    if (formatted && translatable) {
       if (!util::VerifyJavaStringFormat(*string_value->value)) {
         DiagMessage msg(out_resource->source);
         msg << "multiple substitutions specified in non-positional format; "
@@ -631,9 +676,8 @@
       }
     }
 
-  } else if (StyledString* string_value =
-                 ValueCast<StyledString>(out_resource->value.get())) {
-    string_value->SetTranslateable(translateable);
+  } else if (StyledString* string_value = ValueCast<StyledString>(out_resource->value.get())) {
+    string_value->SetTranslatable(translatable);
   }
   return true;
 }
@@ -1048,9 +1092,9 @@
   return true;
 }
 
-bool ResourceParser::ParseStyle(xml::XmlPullParser* parser,
+bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* parser,
                                 ParsedResource* out_resource) {
-  out_resource->name.type = ResourceType::kStyle;
+  out_resource->name.type = type;
 
   std::unique_ptr<Style> style = util::make_unique<Style>();
 
@@ -1136,19 +1180,17 @@
 
   std::unique_ptr<Array> array = util::make_unique<Array>();
 
-  bool translateable = options_.translatable;
-  if (Maybe<StringPiece> translateable_attr =
-          xml::FindAttribute(parser, "translatable")) {
-    Maybe<bool> maybe_translateable =
-        ResourceUtils::ParseBool(translateable_attr.value());
-    if (!maybe_translateable) {
+  bool translatable = options_.translatable;
+  if (Maybe<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
+    Maybe<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
+    if (!maybe_translatable) {
       diag_->Error(DiagMessage(out_resource->source)
                    << "invalid value for 'translatable'. Must be a boolean");
       return false;
     }
-    translateable = maybe_translateable.value();
+    translatable = maybe_translatable.value();
   }
-  array->SetTranslateable(translateable);
+  array->SetTranslatable(translatable);
 
   bool error = false;
   const size_t depth = parser->depth();
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index c12dacf..8258019 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -60,16 +60,16 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(ResourceParser);
 
-  /*
-   * Parses the XML subtree as a StyleString (flattened XML representation for
-   * strings
-   * with formatting). If successful, `out_style_string`
-   * contains the escaped and whitespace trimmed text, while `out_raw_string`
-   * contains the unescaped text. Returns true on success.
-   */
-  bool FlattenXmlSubtree(xml::XmlPullParser* parser,
-                         std::string* out_raw_string,
-                         StyleString* out_style_string);
+  // Parses the XML subtree as a StyleString (flattened XML representation for strings with
+  // formatting). If parsing fails, false is returned and the out parameters are left in an
+  // unspecified state. Otherwise,
+  // `out_style_string` contains the escaped and whitespace trimmed text.
+  // `out_raw_string` contains the un-escaped text.
+  // `out_untranslatable_sections` contains the sections of the string that should not be
+  // translated.
+  bool FlattenXmlSubtree(xml::XmlPullParser* parser, std::string* out_raw_string,
+                         StyleString* out_style_string,
+                         std::vector<UntranslatableSection>* out_untranslatable_sections);
 
   /*
    * Parses the XML subtree and returns an Item.
@@ -102,7 +102,8 @@
                      bool weak);
   Maybe<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
                                                const android::StringPiece& tag);
-  bool ParseStyle(xml::XmlPullParser* parser, ParsedResource* out_resource);
+  bool ParseStyle(const ResourceType type, xml::XmlPullParser* parser,
+                  ParsedResource* out_resource);
   bool ParseStyleItem(xml::XmlPullParser* parser, Style* style);
   bool ParseDeclareStyleable(xml::XmlPullParser* parser,
                              ParsedResource* out_resource);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 5762fb0..67ed476 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -76,6 +76,7 @@
   String* str = test::GetValue<String>(&table_, "string/foo");
   ASSERT_NE(nullptr, str);
   EXPECT_EQ(std::string("  hey there "), *str->value);
+  EXPECT_TRUE(str->untranslatable_sections.empty());
 }
 
 TEST_F(ResourceParserTest, ParseEscapedString) {
@@ -85,6 +86,7 @@
   String* str = test::GetValue<String>(&table_, "string/foo");
   ASSERT_NE(nullptr, str);
   EXPECT_EQ(std::string("?123"), *str->value);
+  EXPECT_TRUE(str->untranslatable_sections.empty());
 }
 
 TEST_F(ResourceParserTest, ParseFormattedString) {
@@ -97,8 +99,7 @@
 
 TEST_F(ResourceParserTest, ParseStyledString) {
   // Use a surrogate pair unicode point so that we can verify that the span
-  // indices
-  // use UTF-16 length and not UTF-18 length.
+  // indices use UTF-16 length and not UTF-8 length.
   std::string input =
       "<string name=\"foo\">This is my aunt\u2019s <b>string</b></string>";
   ASSERT_TRUE(TestParse(input));
@@ -109,6 +110,7 @@
   const std::string expected_str = "This is my aunt\u2019s string";
   EXPECT_EQ(expected_str, *str->value->str);
   EXPECT_EQ(1u, str->value->spans.size());
+  EXPECT_TRUE(str->untranslatable_sections.empty());
 
   EXPECT_EQ(std::string("b"), *str->value->spans[0].name);
   EXPECT_EQ(17u, str->value->spans[0].first_char);
@@ -122,6 +124,7 @@
   String* str = test::GetValue<String>(&table_, "string/foo");
   ASSERT_NE(nullptr, str);
   EXPECT_EQ(std::string("This is what I think"), *str->value);
+  EXPECT_TRUE(str->untranslatable_sections.empty());
 
   input = "<string name=\"foo2\">\"  This is what  I think  \"</string>";
   ASSERT_TRUE(TestParse(input));
@@ -131,16 +134,61 @@
   EXPECT_EQ(std::string("  This is what  I think  "), *str->value);
 }
 
-TEST_F(ResourceParserTest, IgnoreXliffTags) {
-  std::string input =
-      "<string name=\"foo\" \n"
-      "        xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n"
-      "  There are <xliff:g id=\"count\">%1$d</xliff:g> apples</string>";
+TEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
+  std::string input = R"EOF(
+      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+          There are <xliff:source>no</xliff:source> apples</string>)EOF";
+  ASSERT_TRUE(TestParse(input));
+
+  String* str = test::GetValue<String>(&table_, "string/foo");
+  ASSERT_NE(nullptr, str);
+  EXPECT_EQ(StringPiece("There are no apples"), StringPiece(*str->value));
+  EXPECT_TRUE(str->untranslatable_sections.empty());
+}
+
+TEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) {
+  std::string input = R"EOF(
+      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+          Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)EOF";
+  EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) {
+  std::string input = R"EOF(
+      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+          There are <xliff:g id="count">%1$d</xliff:g> apples</string>)EOF";
   ASSERT_TRUE(TestParse(input));
 
   String* str = test::GetValue<String>(&table_, "string/foo");
   ASSERT_NE(nullptr, str);
   EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value));
+
+  ASSERT_EQ(1u, str->untranslatable_sections.size());
+
+  // We expect indices and lengths that span to include the whitespace
+  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
+  // needed (to deal with line breaks, etc.).
+  EXPECT_EQ(9u, str->untranslatable_sections[0].start);
+  EXPECT_EQ(14u, str->untranslatable_sections[0].end);
+}
+
+TEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) {
+  std::string input = R"EOF(
+      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+          There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)EOF";
+  ASSERT_TRUE(TestParse(input));
+
+  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
+  ASSERT_NE(nullptr, str);
+  EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value->str));
+
+  ASSERT_EQ(1u, str->untranslatable_sections.size());
+
+  // We expect indices and lengths that span to include the whitespace
+  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
+  // needed (to deal with line breaks, etc.).
+  EXPECT_EQ(9u, str->untranslatable_sections[0].start);
+  EXPECT_EQ(14u, str->untranslatable_sections[0].end);
 }
 
 TEST_F(ResourceParserTest, ParseNull) {
@@ -149,15 +197,11 @@
 
   // The Android runtime treats a value of android::Res_value::TYPE_NULL as
   // a non-existing value, and this causes problems in styles when trying to
-  // resolve
-  // an attribute. Null values must be encoded as
-  // android::Res_value::TYPE_REFERENCE
+  // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
   // with a data value of 0.
-  BinaryPrimitive* integer =
-      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
+  BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
   ASSERT_NE(nullptr, integer);
-  EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE),
-            integer->value.dataType);
+  EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE), integer->value.dataType);
   EXPECT_EQ(0u, integer->value.data);
 }
 
@@ -719,4 +763,23 @@
   EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
 }
 
+TEST_F(ResourceParserTest, ParseConfigVaryingItem) {
+  std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF";
+  ASSERT_TRUE(TestParse(input));
+  ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo"));
+}
+
+TEST_F(ResourceParserTest, ParseBagElement) {
+  std::string input =
+      R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF";
+  ASSERT_TRUE(TestParse(input));
+
+  Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
+  ASSERT_NE(nullptr, val);
+
+  ASSERT_EQ(1u, val->entries.size());
+  EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key);
+  EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get()));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 1123967..150dc58 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -19,6 +19,7 @@
 #include <sstream>
 
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/ResourceUtils.h"
 
 #include "NameMangler.h"
 #include "SdkConstants.h"
@@ -69,31 +70,6 @@
   return name_out;
 }
 
-bool ExtractResourceName(const StringPiece& str, StringPiece* out_package,
-                         StringPiece* out_type, StringPiece* out_entry) {
-  bool has_package_separator = false;
-  bool has_type_separator = false;
-  const char* start = str.data();
-  const char* end = start + str.size();
-  const char* current = start;
-  while (current != end) {
-    if (out_type->size() == 0 && *current == '/') {
-      has_type_separator = true;
-      out_type->assign(start, current - start);
-      start = current + 1;
-    } else if (out_package->size() == 0 && *current == ':') {
-      has_package_separator = true;
-      out_package->assign(start, current - start);
-      start = current + 1;
-    }
-    current++;
-  }
-  out_entry->assign(start, end - start);
-
-  return !(has_package_separator && out_package->empty()) &&
-         !(has_type_separator && out_type->empty());
-}
-
 bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
                        bool* out_private) {
   if (str.empty()) {
@@ -110,8 +86,8 @@
   StringPiece package;
   StringPiece type;
   StringPiece entry;
-  if (!ExtractResourceName(str.substr(offset, str.size() - offset), &package,
-                           &type, &entry)) {
+  if (!android::ExtractResourceName(str.substr(offset, str.size() - offset), &package, &type,
+                                    &entry)) {
     return false;
   }
 
@@ -197,8 +173,8 @@
     StringPiece package;
     StringPiece type;
     StringPiece entry;
-    if (!ExtractResourceName(trimmed_str.substr(1, trimmed_str.size() - 1),
-                             &package, &type, &entry)) {
+    if (!android::ExtractResourceName(trimmed_str.substr(1, trimmed_str.size() - 1), &package,
+                                      &type, &entry)) {
       return false;
     }
 
@@ -258,7 +234,7 @@
   ref.type = ResourceType::kStyle;
 
   StringPiece type_str;
-  ExtractResourceName(name, &ref.package, &type_str, &ref.entry);
+  android::ExtractResourceName(name, &ref.package, &type_str, &ref.entry);
   if (!type_str.empty()) {
     // If we have a type, make sure it is a Style.
     const ResourceType* parsed_type = ParseResourceType(type_str);
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index bd3a8e3..59b78f4 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -29,18 +29,6 @@
 namespace aapt {
 namespace ResourceUtils {
 
-/*
- * Extracts the package, type, and name from a string of the format:
- *
- *      [package:]type/name
- *
- * where the package can be empty. Validation must be performed on each
- * individual extracted piece to verify that the pieces are valid.
- * Returns false if there was no package but a ':' was present.
- */
-bool ExtractResourceName(const android::StringPiece& str, android::StringPiece* out_package,
-                         android::StringPiece* out_type, android::StringPiece* out_entry);
-
 /**
  * Returns true if the string was parsed as a resource name
  * ([*][package:]type/name), with
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 7956ad8..f75ed7a 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -140,7 +140,23 @@
   if (!other) {
     return false;
   }
-  return *this->value == *other->value;
+
+  if (this->value != other->value) {
+    return false;
+  }
+
+  if (untranslatable_sections.size() != other->untranslatable_sections.size()) {
+    return false;
+  }
+
+  auto other_iter = other->untranslatable_sections.begin();
+  for (const UntranslatableSection& this_section : untranslatable_sections) {
+    if (this_section != *other_iter) {
+      return false;
+    }
+    ++other_iter;
+  }
+  return true;
 }
 
 bool String::Flatten(android::Res_value* out_value) const {
@@ -158,6 +174,7 @@
   String* str = new String(new_pool->MakeRef(*value));
   str->comment_ = comment_;
   str->source_ = source_;
+  str->untranslatable_sections = untranslatable_sections;
   return str;
 }
 
@@ -173,17 +190,22 @@
     return false;
   }
 
-  if (*this->value->str == *other->value->str) {
-    const std::vector<StringPool::Span>& spans_a = this->value->spans;
-    const std::vector<StringPool::Span>& spans_b = other->value->spans;
-    return std::equal(
-        spans_a.begin(), spans_a.end(), spans_b.begin(),
-        [](const StringPool::Span& a, const StringPool::Span& b) -> bool {
-          return *a.name == *b.name && a.first_char == b.first_char &&
-                 a.last_char == b.last_char;
-        });
+  if (this->value != other->value) {
+    return false;
   }
-  return false;
+
+  if (untranslatable_sections.size() != other->untranslatable_sections.size()) {
+    return false;
+  }
+
+  auto other_iter = other->untranslatable_sections.begin();
+  for (const UntranslatableSection& this_section : untranslatable_sections) {
+    if (this_section != *other_iter) {
+      return false;
+    }
+    ++other_iter;
+  }
+  return true;
 }
 
 bool StyledString::Flatten(android::Res_value* out_value) const {
@@ -200,6 +222,7 @@
   StyledString* str = new StyledString(new_pool->MakeRef(value));
   str->comment_ = comment_;
   str->source_ = source_;
+  str->untranslatable_sections = untranslatable_sections;
   return str;
 }
 
@@ -218,7 +241,7 @@
   if (!other) {
     return false;
   }
-  return *path == *other->path;
+  return path == other->path;
 }
 
 bool FileReference::Flatten(android::Res_value* out_value) const {
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index d380f8d..c71c738 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -34,44 +34,35 @@
 
 struct RawValueVisitor;
 
-/**
- * A resource value. This is an all-encompassing representation
- * of Item and Map and their subclasses. The way to do
- * type specific operations is to check the Value's type() and
- * cast it to the appropriate subclass. This isn't super clean,
- * but it is the simplest strategy.
- */
+// A resource value. This is an all-encompassing representation
+// of Item and Map and their subclasses. The way to do
+// type specific operations is to check the Value's type() and
+// cast it to the appropriate subclass. This isn't super clean,
+// but it is the simplest strategy.
 struct Value {
   virtual ~Value() = default;
 
-  /**
-   * Whether this value is weak and can be overridden without
-   * warning or error. Default is false.
-   */
+  // Whether this value is weak and can be overridden without warning or error. Default is false.
   bool IsWeak() const { return weak_; }
 
   void SetWeak(bool val) { weak_ = val; }
 
-  // Whether the value is marked as translateable.
+  // Whether the value is marked as translatable.
   // This does not persist when flattened.
   // It is only used during compilation phase.
-  void SetTranslateable(bool val) { translateable_ = val; }
+  void SetTranslatable(bool val) { translatable_ = val; }
 
   // Default true.
-  bool IsTranslateable() const { return translateable_; }
+  bool IsTranslatable() const { return translatable_; }
 
-  /**
-   * Returns the source where this value was defined.
-   */
+  // Returns the source where this value was defined.
   const Source& GetSource() const { return source_; }
 
   void SetSource(const Source& source) { source_ = source; }
 
   void SetSource(Source&& source) { source_ = std::move(source); }
 
-  /**
-   * Returns the comment that was associated with this resource.
-   */
+  // Returns the comment that was associated with this resource.
   const std::string& GetComment() const { return comment_; }
 
   void SetComment(const android::StringPiece& str) { comment_ = str.to_string(); }
@@ -80,70 +71,48 @@
 
   virtual bool Equals(const Value* value) const = 0;
 
-  /**
-   * Calls the appropriate overload of ValueVisitor.
-   */
+  // Calls the appropriate overload of ValueVisitor.
   virtual void Accept(RawValueVisitor* visitor) = 0;
 
-  /**
-   * Clone the value. new_pool is the new StringPool that
-   * any resources with strings should use when copying their string.
-   */
+  // Clone the value. `new_pool` is the new StringPool that
+  // any resources with strings should use when copying their string.
   virtual Value* Clone(StringPool* new_pool) const = 0;
 
-  /**
-   * Human readable printout of this value.
-   */
+  // Human readable printout of this value.
   virtual void Print(std::ostream* out) const = 0;
 
  protected:
   Source source_;
   std::string comment_;
   bool weak_ = false;
-  bool translateable_ = true;
+  bool translatable_ = true;
 };
 
-/**
- * Inherit from this to get visitor accepting implementations for free.
- */
+// Inherit from this to get visitor accepting implementations for free.
 template <typename Derived>
 struct BaseValue : public Value {
   void Accept(RawValueVisitor* visitor) override;
 };
 
-/**
- * A resource item with a single value. This maps to android::ResTable_entry.
- */
+// A resource item with a single value. This maps to android::ResTable_entry.
 struct Item : public Value {
-  /**
-   * Clone the Item.
-   */
+  // Clone the Item.
   virtual Item* Clone(StringPool* new_pool) const override = 0;
 
-  /**
-   * Fills in an android::Res_value structure with this Item's binary
-   * representation.
-   * Returns false if an error occurred.
-   */
+  // Fills in an android::Res_value structure with this Item's binary representation.
+  // Returns false if an error occurred.
   virtual bool Flatten(android::Res_value* out_value) const = 0;
 };
 
-/**
- * Inherit from this to get visitor accepting implementations for free.
- */
+// Inherit from this to get visitor accepting implementations for free.
 template <typename Derived>
 struct BaseItem : public Item {
   void Accept(RawValueVisitor* visitor) override;
 };
 
-/**
- * A reference to another resource. This maps to
- * android::Res_value::TYPE_REFERENCE.
- *
- * A reference can be symbolic (with the name set to a valid resource name) or
- * be
- * numeric (the id is set to a valid resource ID).
- */
+// A reference to another resource. This maps to android::Res_value::TYPE_REFERENCE.
+// A reference can be symbolic (with the name set to a valid resource name) or be
+// numeric (the id is set to a valid resource ID).
 struct Reference : public BaseItem<Reference> {
   enum class Type {
     kResource,
@@ -169,9 +138,7 @@
 bool operator<(const Reference&, const Reference&);
 bool operator==(const Reference&, const Reference&);
 
-/**
- * An ID resource. Has no real value, just a place holder.
- */
+// An ID resource. Has no real value, just a place holder.
 struct Id : public BaseItem<Id> {
   Id() { weak_ = true; }
   bool Equals(const Value* value) const override;
@@ -180,11 +147,8 @@
   void Print(std::ostream* out) const override;
 };
 
-/**
- * A raw, unprocessed string. This may contain quotations,
- * escape sequences, and whitespace. This shall *NOT*
- * end up in the final resource table.
- */
+// A raw, unprocessed string. This may contain quotations, escape sequences, and whitespace.
+// This shall *NOT* end up in the final resource table.
 struct RawString : public BaseItem<RawString> {
   StringPool::Ref value;
 
@@ -196,9 +160,32 @@
   void Print(std::ostream* out) const override;
 };
 
+// Identifies a range of characters in a string that are untranslatable.
+// These should not be pseudolocalized. The start and end indices are measured in bytes.
+struct UntranslatableSection {
+  // Start offset inclusive.
+  size_t start;
+
+  // End offset exclusive.
+  size_t end;
+};
+
+inline bool operator==(const UntranslatableSection& a, const UntranslatableSection& b) {
+  return a.start == b.start && a.end == b.end;
+}
+
+inline bool operator!=(const UntranslatableSection& a, const UntranslatableSection& b) {
+  return a.start != b.start || a.end != b.end;
+}
+
 struct String : public BaseItem<String> {
   StringPool::Ref value;
 
+  // Sections of the string to NOT translate. Mainly used
+  // for pseudolocalization. This data is NOT persisted
+  // in any format.
+  std::vector<UntranslatableSection> untranslatable_sections;
+
   explicit String(const StringPool::Ref& ref);
 
   bool Equals(const Value* value) const override;
@@ -210,6 +197,11 @@
 struct StyledString : public BaseItem<StyledString> {
   StringPool::StyleRef value;
 
+  // Sections of the string to NOT translate. Mainly used
+  // for pseudolocalization. This data is NOT persisted
+  // in any format.
+  std::vector<UntranslatableSection> untranslatable_sections;
+
   explicit StyledString(const StringPool::StyleRef& ref);
 
   bool Equals(const Value* value) const override;
@@ -221,9 +213,8 @@
 struct FileReference : public BaseItem<FileReference> {
   StringPool::Ref path;
 
-  /**
-   * A handle to the file object from which this file can be read.
-   */
+  // A handle to the file object from which this file can be read.
+  // This field is NOT persisted in any format. It is transient.
   io::IFile* file = nullptr;
 
   FileReference() = default;
@@ -235,9 +226,7 @@
   void Print(std::ostream* out) const override;
 };
 
-/**
- * Represents any other android::Res_value.
- */
+// Represents any other android::Res_value.
 struct BinaryPrimitive : public BaseItem<BinaryPrimitive> {
   android::Res_value value;
 
@@ -279,10 +268,7 @@
 
   Maybe<Reference> parent;
 
-  /**
-   * If set to true, the parent was auto inferred from the
-   * style's name.
-   */
+  // If set to true, the parent was auto inferred from the style's name.
   bool parent_inferred = false;
 
   std::vector<Entry> entries;
@@ -319,9 +305,7 @@
   void MergeWith(Styleable* styleable);
 };
 
-/**
- * Stream operator for printing Value objects.
- */
+// Stream operator for printing Value objects.
 inline ::std::ostream& operator<<(::std::ostream& out, const Value& value) {
   value.Print(&out);
   return out;
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 6acb4d3..ad4e3ce 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -49,6 +49,10 @@
   ASSERT_NE(type, nullptr);
   EXPECT_EQ(*type, ResourceType::kColor);
 
+  type = ParseResourceType("configVarying");
+  ASSERT_NE(type, nullptr);
+  EXPECT_EQ(*type, ResourceType::kConfigVarying);
+
   type = ParseResourceType("dimen");
   ASSERT_NE(type, nullptr);
   EXPECT_EQ(*type, ResourceType::kDimen);
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index d968d73..57da5f0 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -63,6 +63,14 @@
   return *this;
 }
 
+bool StringPool::Ref::operator==(const Ref& rhs) const {
+  return entry_->value == rhs.entry_->value;
+}
+
+bool StringPool::Ref::operator!=(const Ref& rhs) const {
+  return entry_->value != rhs.entry_->value;
+}
+
 const std::string* StringPool::Ref::operator->() const {
   return &entry_->value;
 }
@@ -109,6 +117,28 @@
   return *this;
 }
 
+bool StringPool::StyleRef::operator==(const StyleRef& rhs) const {
+  if (entry_->str != rhs.entry_->str) {
+    return false;
+  }
+
+  if (entry_->spans.size() != rhs.entry_->spans.size()) {
+    return false;
+  }
+
+  auto rhs_iter = rhs.entry_->spans.begin();
+  for (const Span& span : entry_->spans) {
+    const Span& rhs_span = *rhs_iter;
+    if (span.first_char != rhs_span.first_char || span.last_char != rhs_span.last_char ||
+        span.name != rhs_span.name) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool StringPool::StyleRef::operator!=(const StyleRef& rhs) const { return !operator==(rhs); }
+
 const StringPool::StyleEntry* StringPool::StyleRef::operator->() const {
   return entry_;
 }
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
index d0ce489..a626d37 100644
--- a/tools/aapt2/StringPool.h
+++ b/tools/aapt2/StringPool.h
@@ -70,6 +70,8 @@
     ~Ref();
 
     Ref& operator=(const Ref& rhs);
+    bool operator==(const Ref& rhs) const;
+    bool operator!=(const Ref& rhs) const;
     const std::string* operator->() const;
     const std::string& operator*() const;
 
@@ -93,6 +95,8 @@
     ~StyleRef();
 
     StyleRef& operator=(const StyleRef& rhs);
+    bool operator==(const StyleRef& rhs) const;
+    bool operator!=(const StyleRef& rhs) const;
     const StyleEntry* operator->() const;
     const StyleEntry& operator*() const;
 
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 5035f81..fad9edd 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -43,16 +43,16 @@
   }
 
   // The ranges are all represented with a single value. This is the start of
-  // one range and
-  // end of another.
+  // one range and end of another.
   struct Range {
     size_t start;
 
-    // Once the new string is localized, these are the pointers to the spans to
-    // adjust.
+    // If set to true, toggles the state of translatability.
+    bool toggle_translatability;
+
+    // Once the new string is localized, these are the pointers to the spans to adjust.
     // Since this struct represents the start of one range and end of another,
-    // we have
-    // the two pointers respectively.
+    // we have the two pointers respectively.
     uint32_t* update_start;
     uint32_t* update_end;
   };
@@ -63,12 +63,11 @@
 
   // Construct the ranges. The ranges are represented like so: [0, 2, 5, 7]
   // The ranges are the spaces in between. In this example, with a total string
-  // length of 9,
-  // the vector represents: (0,1], (2,4], (5,6], (7,9]
+  // length of 9, the vector represents: (0,1], (2,4], (5,6], (7,9]
   //
   std::vector<Range> ranges;
-  ranges.push_back(Range{0});
-  ranges.push_back(Range{original_text.size() - 1});
+  ranges.push_back(Range{0, false, nullptr, nullptr});
+  ranges.push_back(Range{original_text.size() - 1, false, nullptr, nullptr});
   for (size_t i = 0; i < string->value->spans.size(); i++) {
     const StringPool::Span& span = string->value->spans[i];
 
@@ -78,8 +77,7 @@
     if (iter != ranges.end() && iter->start == span.first_char) {
       iter->update_start = &localized.spans[i].first_char;
     } else {
-      ranges.insert(iter, Range{span.first_char, &localized.spans[i].first_char,
-                                nullptr});
+      ranges.insert(iter, Range{span.first_char, false, &localized.spans[i].first_char, nullptr});
     }
 
     // Insert or update the Range marker for the end of this span.
@@ -87,14 +85,45 @@
     if (iter != ranges.end() && iter->start == span.last_char) {
       iter->update_end = &localized.spans[i].last_char;
     } else {
-      ranges.insert(
-          iter, Range{span.last_char, nullptr, &localized.spans[i].last_char});
+      ranges.insert(iter, Range{span.last_char, false, nullptr, &localized.spans[i].last_char});
+    }
+  }
+
+  // Parts of the string may be untranslatable. Merge those ranges
+  // in as well, so that we have continuous sections of text to
+  // feed into the pseudolocalizer.
+  // We do this by marking the beginning of a range as either toggling
+  // the translatability state or not.
+  for (const UntranslatableSection& section : string->untranslatable_sections) {
+    auto iter = std::lower_bound(ranges.begin(), ranges.end(), section.start, cmp);
+    if (iter != ranges.end() && iter->start == section.start) {
+      // An existing span starts (or ends) here. We just need to mark that
+      // the translatability should toggle here. If translatability was
+      // already being toggled, then that means we have two adjacent ranges of untranslatable
+      // text, so remove the toggle and only toggle at the end of this range,
+      // effectively merging these ranges.
+      iter->toggle_translatability = !iter->toggle_translatability;
+    } else {
+      // Insert a new range that specifies to toggle the translatability.
+      iter = ranges.insert(iter, Range{section.start, true, nullptr, nullptr});
+    }
+
+    // Update/create an end to the untranslatable section.
+    iter = std::lower_bound(iter, ranges.end(), section.end, cmp);
+    if (iter != ranges.end() && iter->start == section.end) {
+      iter->toggle_translatability = true;
+    } else {
+      iter = ranges.insert(iter, Range{section.end, true, nullptr, nullptr});
     }
   }
 
   localized.str += localizer.Start();
 
   // Iterate over the ranges and localize each section.
+  // The text starts as translatable, and each time a range has toggle_translatability
+  // set to true, we toggle whether to translate or not.
+  // This assumes no untranslatable ranges overlap.
+  bool translatable = true;
   for (size_t i = 0; i < ranges.size(); i++) {
     const size_t start = ranges[i].start;
     size_t len = original_text.size() - start;
@@ -110,15 +139,20 @@
       *ranges[i].update_end = localized.str.size();
     }
 
-    localized.str += localizer.Text(original_text.substr(start, len));
+    if (ranges[i].toggle_translatability) {
+      translatable = !translatable;
+    }
+
+    if (translatable) {
+      localized.str += localizer.Text(original_text.substr(start, len));
+    } else {
+      localized.str += original_text.substr(start, len);
+    }
   }
 
   localized.str += localizer.End();
 
-  std::unique_ptr<StyledString> localized_string =
-      util::make_unique<StyledString>(pool->MakeRef(localized));
-  localized_string->SetSource(string->GetSource());
-  return localized_string;
+  return util::make_unique<StyledString>(pool->MakeRef(localized));
 }
 
 namespace {
@@ -152,8 +186,30 @@
   }
 
   void Visit(String* string) override {
-    std::string result =
-        localizer_.Start() + localizer_.Text(*string->value) + localizer_.End();
+    const StringPiece original_string = *string->value;
+    std::string result = localizer_.Start();
+
+    // Pseudolocalize only the translatable sections.
+    size_t start = 0u;
+    for (const UntranslatableSection& section : string->untranslatable_sections) {
+      // Pseudolocalize the content before the untranslatable section.
+      const size_t len = section.start - start;
+      if (len > 0u) {
+        result += localizer_.Text(original_string.substr(start, len));
+      }
+
+      // Copy the untranslatable content.
+      result += original_string.substr(section.start, section.end - section.start);
+      start = section.end;
+    }
+
+    // Pseudolocalize the content after the last untranslatable section.
+    if (start != original_string.size()) {
+      const size_t len = original_string.size() - start;
+      result += localizer_.Text(original_string.substr(start, len));
+    }
+    result += localizer_.End();
+
     std::unique_ptr<String> localized =
         util::make_unique<String>(pool_->MakeRef(result));
     localized->SetSource(string->GetSource());
@@ -163,6 +219,7 @@
 
   void Visit(StyledString* string) override {
     item = PseudolocalizeStyledString(string, method_, pool_);
+    item->SetSource(string->GetSource());
     item->SetWeak(true);
   }
 
@@ -228,7 +285,7 @@
 /**
  * A value is pseudolocalizable if it does not define a locale (or is the
  * default locale)
- * and is translateable.
+ * and is translatable.
  */
 static bool IsPseudolocalizable(ResourceConfigValue* config_value) {
   const int diff =
@@ -236,7 +293,7 @@
   if (diff & ConfigDescription::CONFIG_LOCALE) {
     return false;
   }
-  return config_value->value->IsTranslateable();
+  return config_value->value->IsTranslatable();
 }
 
 }  // namespace
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
index 5a9884d..4db37db 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -89,7 +89,7 @@
 
   String* val = test::GetValue<String>(table.get(), "android:string/four");
   ASSERT_NE(nullptr, val);
-  val->SetTranslateable(false);
+  val->SetTranslatable(false);
 
   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
   PseudolocaleGenerator generator;
@@ -130,4 +130,47 @@
                                             test::ParseConfigOrDie("ar-rXB")));
 }
 
+TEST(PseudolocaleGeneratorTest, RespectUntranslateableSections) {
+  std::unique_ptr<IAaptContext> context =
+      test::ContextBuilder().SetCompilationPackage("android").Build();
+  std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+
+  {
+    StyleString original_style;
+    original_style.str = "Hello world!";
+    original_style.spans = {Span{"b", 2, 3}, Span{"b", 6, 7}, Span{"i", 1, 10}};
+
+    auto styled_string =
+        util::make_unique<StyledString>(table->string_pool.MakeRef(original_style));
+    styled_string->untranslatable_sections.push_back(UntranslatableSection{6u, 8u});
+    styled_string->untranslatable_sections.push_back(UntranslatableSection{8u, 11u});
+
+    auto string = util::make_unique<String>(table->string_pool.MakeRef(original_style.str));
+    string->untranslatable_sections.push_back(UntranslatableSection{6u, 11u});
+
+    ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("android:string/foo"), ConfigDescription{},
+                                   {} /* product */, std::move(styled_string),
+                                   context->GetDiagnostics()));
+    ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("android:string/bar"), ConfigDescription{},
+                                   {} /* product */, std::move(string), context->GetDiagnostics()));
+  }
+
+  PseudolocaleGenerator generator;
+  ASSERT_TRUE(generator.Consume(context.get(), table.get()));
+
+  StyledString* new_styled_string = test::GetValueForConfig<StyledString>(
+      table.get(), "android:string/foo", test::ParseConfigOrDie("en-rXA"));
+  ASSERT_NE(nullptr, new_styled_string);
+
+  // "world" should be untranslated.
+  EXPECT_NE(std::string::npos, new_styled_string->value->str->find("world"));
+
+  String* new_string = test::GetValueForConfig<String>(table.get(), "android:string/bar",
+                                                       test::ParseConfigOrDie("en-rXA"));
+  ASSERT_NE(nullptr, new_string);
+
+  // "world" should be untranslated.
+  EXPECT_NE(std::string::npos, new_string->value->find("world"));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index e5eaf2f..b4cf4f8 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -111,6 +111,36 @@
   return true;
 }
 
+// Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
+static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
+  bool has_name = false;
+  if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
+    if (attr->value.empty()) {
+      diag->Error(DiagMessage(el->line_number)
+                  << "android:name in <uses-feature> must not be empty");
+      return false;
+    }
+    has_name = true;
+  }
+
+  bool has_gl_es_version = false;
+  if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
+    if (has_name) {
+      diag->Error(DiagMessage(el->line_number)
+                  << "cannot define both android:name and android:glEsVersion in <uses-feature>");
+      return false;
+    }
+    has_gl_es_version = true;
+  }
+
+  if (!has_name && !has_gl_es_version) {
+    diag->Error(DiagMessage(el->line_number)
+                << "<uses-feature> must have either android:name or android:glEsVersion attribute");
+    return false;
+  }
+  return true;
+}
+
 bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
                                IDiagnostics* diag) {
   // First verify some options.
@@ -134,15 +164,25 @@
     }
   }
 
-  // Common intent-filter actions.
+  // Common <intent-filter> actions.
   xml::XmlNodeAction intent_filter_action;
   intent_filter_action["action"];
   intent_filter_action["category"];
   intent_filter_action["data"];
 
-  // Common meta-data actions.
+  // Common <meta-data> actions.
   xml::XmlNodeAction meta_data_action;
 
+  // Common <uses-feature> actions.
+  xml::XmlNodeAction uses_feature_action;
+  uses_feature_action.Action(VerifyUsesFeature);
+
+  // Common component actions.
+  xml::XmlNodeAction component_action;
+  component_action.Action(RequiredNameIsJavaClassName);
+  component_action["intent-filter"] = intent_filter_action;
+  component_action["meta-data"] = meta_data_action;
+
   // Manifest actions.
   xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
   manifest_action.Action(VerifyManifest);
@@ -190,6 +230,7 @@
   });
 
   // Instrumentation actions.
+  manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
   manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
     if (!options_.rename_instrumentation_target_package) {
       return true;
@@ -201,6 +242,7 @@
     }
     return true;
   });
+  manifest_action["instrumentation"]["meta-data"] = meta_data_action;
 
   manifest_action["original-package"];
   manifest_action["protected-broadcast"];
@@ -208,51 +250,28 @@
   manifest_action["permission"];
   manifest_action["permission-tree"];
   manifest_action["permission-group"];
-
   manifest_action["uses-configuration"];
-  manifest_action["uses-feature"];
   manifest_action["supports-screens"];
-
+  manifest_action["uses-feature"] = uses_feature_action;
+  manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
   manifest_action["compatible-screens"];
   manifest_action["compatible-screens"]["screen"];
-
   manifest_action["supports-gl-texture"];
-
   manifest_action["meta-data"] = meta_data_action;
 
   // Application actions.
   xml::XmlNodeAction& application_action = manifest_action["application"];
   application_action.Action(OptionalNameIsJavaClassName);
 
-  // Uses library actions.
   application_action["uses-library"];
-
-  // Meta-data.
   application_action["meta-data"] = meta_data_action;
-
-  // Activity actions.
-  application_action["activity"].Action(RequiredNameIsJavaClassName);
-  application_action["activity"]["intent-filter"] = intent_filter_action;
-  application_action["activity"]["meta-data"] = meta_data_action;
-
-  // Activity alias actions.
-  application_action["activity-alias"]["intent-filter"] = intent_filter_action;
-  application_action["activity-alias"]["meta-data"] = meta_data_action;
-
-  // Service actions.
-  application_action["service"].Action(RequiredNameIsJavaClassName);
-  application_action["service"]["intent-filter"] = intent_filter_action;
-  application_action["service"]["meta-data"] = meta_data_action;
-
-  // Receiver actions.
-  application_action["receiver"].Action(RequiredNameIsJavaClassName);
-  application_action["receiver"]["intent-filter"] = intent_filter_action;
-  application_action["receiver"]["meta-data"] = meta_data_action;
+  application_action["activity"] = component_action;
+  application_action["activity-alias"] = component_action;
+  application_action["service"] = component_action;
+  application_action["receiver"] = component_action;
 
   // Provider actions.
-  application_action["provider"].Action(RequiredNameIsJavaClassName);
-  application_action["provider"]["intent-filter"] = intent_filter_action;
-  application_action["provider"]["meta-data"] = meta_data_action;
+  application_action["provider"] = component_action;
   application_action["provider"]["grant-uri-permissions"];
   application_action["provider"]["path-permissions"];
 
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 12a304a..ce84993 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -90,7 +90,7 @@
 }
 
 TEST_F(ManifestFixerTest, AllowMetaData) {
-    auto doc = Verify(R"EOF(
+  auto doc = Verify(R"EOF(
         <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                   package="android">
           <meta-data />
@@ -98,12 +98,13 @@
             <meta-data />
             <activity android:name=".Hi"><meta-data /></activity>
             <activity-alias android:name=".Ho"><meta-data /></activity-alias>
-            <receiver android:name=".OffToWork"><meta-data /></receiver>
-            <provider android:name=".We"><meta-data /></provider>
-            <service android:name=".Go"><meta-data /></service>
+            <receiver android:name=".OffTo"><meta-data /></receiver>
+            <provider android:name=".Work"><meta-data /></provider>
+            <service android:name=".We"><meta-data /></service>
           </application>
+          <instrumentation android:name=".Go"><meta-data /></instrumentation>
         </manifest>)EOF");
-    ASSERT_NE(nullptr, doc);
+  ASSERT_NE(nullptr, doc);
 }
 
 TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
@@ -290,7 +291,7 @@
   std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
       <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                 package="android">
-        <instrumentation android:targetPackage="android" />
+        <instrumentation android:name=".TestRunner" android:targetPackage="android" />
       </manifest>)EOF",
                                                             options);
   ASSERT_NE(nullptr, doc);
@@ -354,4 +355,51 @@
   EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
 }
 
+TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
+  std::string input = R"EOF(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  package="android">
+          <uses-feature android:name="feature" />
+          <uses-feature android:glEsVersion="1" />
+          <feature-group />
+          <feature-group>
+            <uses-feature android:name="feature_in_group" />
+            <uses-feature android:glEsVersion="2" />
+          </feature-group>
+        </manifest>)EOF";
+  EXPECT_NE(nullptr, Verify(input));
+
+  input = R"EOF(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  package="android">
+          <uses-feature android:name="feature" android:glEsVersion="1" />
+        </manifest>)EOF";
+  EXPECT_EQ(nullptr, Verify(input));
+
+  input = R"EOF(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  package="android">
+          <uses-feature />
+        </manifest>)EOF";
+  EXPECT_EQ(nullptr, Verify(input));
+
+  input = R"EOF(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  package="android">
+          <feature-group>
+            <uses-feature android:name="feature" android:glEsVersion="1" />
+          </feature-group>
+        </manifest>)EOF";
+  EXPECT_EQ(nullptr, Verify(input));
+
+  input = R"EOF(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  package="android">
+          <feature-group>
+            <uses-feature />
+          </feature-group>
+        </manifest>)EOF";
+  EXPECT_EQ(nullptr, Verify(input));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index e2a752e..8bc4e8c 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,5 +1,16 @@
 # Android Asset Packaging Tool 2.0 (AAPT2) release notes
 
+## Version 2.7
+### `aapt2 compile`
+- Fixes bug where psuedolocalization auto-translated strings marked 'translateable="false"'.
+
+## Version 2.6
+### `aapt2`
+- Support legacy `configVarying` resource type.
+- Support `<bag>` tag and treat as `<style>` regardless of type.
+- Add `<feature-group>` manifest tag verification.
+- Add `<meta-data>` tag support to `<instrumentation>`.
+
 ## Version 2.5
 ### `aapt2 link ...`
 - Transition XML versioning: Adds a new flag `--no-version-transitions` to disable automatic
diff --git a/tools/layoutlib/.idea/libraries/mockito.xml b/tools/layoutlib/.idea/libraries/mockito.xml
new file mode 100644
index 0000000..032963e
--- /dev/null
+++ b/tools/layoutlib/.idea/libraries/mockito.xml
@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="mockito">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/mockito-host_intermediates/javalib.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/libraries/objenesis.xml b/tools/layoutlib/.idea/libraries/objenesis.xml
new file mode 100644
index 0000000..1484de5
--- /dev/null
+++ b/tools/layoutlib/.idea/libraries/objenesis.xml
@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="objenesis">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/objenesis-host_intermediates/javalib.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/bridge.iml b/tools/layoutlib/bridge/bridge.iml
index fbaed52..85ec3eb 100644
--- a/tools/layoutlib/bridge/bridge.iml
+++ b/tools/layoutlib/bridge/bridge.iml
@@ -86,5 +86,7 @@
       </library>
     </orderEntry>
     <orderEntry type="library" scope="TEST" name="junit" level="project" />
+    <orderEntry type="library" scope="TEST" name="mockito" level="project" />
+    <orderEntry type="library" scope="TEST" name="objenesis" level="project" />
   </component>
 </module>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java
index 138b2d5..9fd1e15 100644
--- a/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java
+++ b/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java
@@ -16,6 +16,7 @@
 
 package android.util;
 
+import com.android.ide.common.rendering.api.AttrResourceValue;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.internal.util.XmlUtils;
@@ -27,6 +28,11 @@
 
 import org.xmlpull.v1.XmlPullParser;
 
+import android.annotation.NonNull;
+
+import java.util.Map;
+import java.util.function.Function;
+
 /**
  * A correct implementation of the {@link AttributeSet} interface on top of a XmlPullParser
  */
@@ -34,12 +40,30 @@
 
     private final BridgeContext mContext;
     private final boolean mPlatformFile;
+    private final Function<String, Map<String, Integer>> mFrameworkEnumValueSupplier;
+    private final Function<String, Map<String, Integer>> mProjectEnumValueSupplier;
 
-    public BridgeXmlPullAttributes(XmlPullParser parser, BridgeContext context,
-            boolean platformFile) {
+    // VisibleForTesting
+    BridgeXmlPullAttributes(@NonNull XmlPullParser parser, @NonNull BridgeContext context,
+            boolean platformFile,
+            @NonNull Function<String, Map<String, Integer>> frameworkEnumValueSupplier,
+            @NonNull Function<String, Map<String, Integer>> projectEnumValueSupplier) {
         super(parser);
         mContext = context;
         mPlatformFile = platformFile;
+        mFrameworkEnumValueSupplier = frameworkEnumValueSupplier;
+        mProjectEnumValueSupplier = projectEnumValueSupplier;
+    }
+
+    public BridgeXmlPullAttributes(@NonNull XmlPullParser parser, @NonNull BridgeContext context,
+            boolean platformFile) {
+        this(parser, context, platformFile, Bridge::getEnumValues, attrName -> {
+            // get the styleable matching the resolved name
+            RenderResources res = context.getRenderResources();
+            ResourceValue attr = res.getProjectResource(ResourceType.ATTR, attrName);
+            return attr instanceof AttrResourceValue ?
+                    ((AttrResourceValue) attr).getAttributeValues() : null;
+        });
     }
 
     /*
@@ -59,12 +83,8 @@
         String ns = mParser.getAttributeNamespace(index);
 
         if (BridgeConstants.NS_RESOURCES.equals(ns)) {
-            Integer v = Bridge.getResourceId(ResourceType.ATTR, name);
-            if (v != null) {
-                return v.intValue();
-            }
+            return Bridge.getResourceId(ResourceType.ATTR, name);
 
-            return 0;
         }
 
         // this is not an attribute in the android namespace, we query the customviewloader, if
@@ -72,7 +92,7 @@
         if (mContext.getLayoutlibCallback().getNamespace().equals(ns)) {
             Integer v = mContext.getLayoutlibCallback().getResourceId(ResourceType.ATTR, name);
             if (v != null) {
-                return v.intValue();
+                return v;
             }
         }
 
@@ -121,20 +141,38 @@
     }
 
     @Override
-    public int getAttributeIntValue(String namespace, String attribute,
-            int defaultValue) {
+    public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
         String value = getAttributeValue(namespace, attribute);
-        if (value != null) {
-            ResourceValue r = getResourceValue(value);
-
-            if (r != null) {
-                value = r.getValue();
-            }
-
-            return XmlUtils.convertValueToInt(value, defaultValue);
+        if (value == null) {
+            return defaultValue;
         }
 
-        return defaultValue;
+        ResourceValue r = getResourceValue(value);
+
+        if (r != null) {
+            value = r.getValue();
+        }
+
+        if (value.charAt(0) == '#') {
+            return ResourceHelper.getColor(value);
+        }
+
+        try {
+            return XmlUtils.convertValueToInt(value, defaultValue);
+        } catch (NumberFormatException e) {
+            // This is probably an enum
+            Map<String, Integer> enumValues = BridgeConstants.NS_RESOURCES.equals(namespace) ?
+                    mFrameworkEnumValueSupplier.apply(attribute) :
+                    mProjectEnumValueSupplier.apply(attribute);
+
+            Integer enumValue = enumValues != null ? enumValues.get(value) : null;
+            if (enumValue != null) {
+                return enumValue;
+            }
+
+            // We weren't able to find the enum int value
+            throw e;
+        }
     }
 
     @Override
@@ -203,21 +241,9 @@
 
     @Override
     public int getAttributeIntValue(int index, int defaultValue) {
-        String value = getAttributeValue(index);
-        if (value != null) {
-            ResourceValue r = getResourceValue(value);
-
-            if (r != null) {
-                value = r.getValue();
-            }
-
-            if (value.charAt(0) == '#') {
-                return ResourceHelper.getColor(value);
-            }
-            return XmlUtils.convertValueToInt(value, defaultValue);
-        }
-
-        return defaultValue;
+        return getAttributeIntValue(mParser.getAttributeNamespace(index),
+                getAttributeName(index)
+                , defaultValue);
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 56898f1..253ea6f 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -483,16 +483,6 @@
     }
 
     @Override
-    public Rect getPictureInPictureDefaultBounds(int displayId) {
-        return null;
-    }
-
-    @Override
-    public Rect getPictureInPictureMovementBounds(int displayId)  {
-        return null;
-    }
-
-    @Override
     public void setResizeDimLayer(boolean visible, int targetStackId, float alpha)
             throws RemoteException {
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index dff4f69..c9b04dc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -111,7 +111,7 @@
  * Custom implementation of Context/Activity to handle non compiled resources.
  */
 @SuppressWarnings("deprecation")  // For use of Pair.
-public final class BridgeContext extends Context {
+public class BridgeContext extends Context {
     private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat";
 
     private static final Map<String, ResourceValue> FRAMEWORK_PATCHED_VALUES = new HashMap<>(2);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index ab73a8b..468710b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -248,4 +248,9 @@
         // TODO Auto-generated method stub
         return null;
     }
+
+    @Override
+    public void reportFullscreenMode(IBinder token, boolean fullscreen) {
+        // TODO Auto-generated method stub
+    }
 }
diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
index 33d55de..1b65eee 100644
--- a/tools/layoutlib/bridge/tests/Android.mk
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -31,7 +31,8 @@
 			tools-common-prebuilt \
 			sdk-common \
 			junit-host \
-			guavalib
+			guavalib \
+			mockito-host
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
index 199ea60..affc31e 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
index 89ff5db..a53dcba 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
index 1f4405d..88fa9dd 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
index 26aed6a..e33f92d 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
index aaf1514..915868c 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
index c3bd708..ee72a6f 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
index 0c16215..781d617 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
index 81755ce..5b64d33 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
index 868cd51..a8567b3 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
index 601f711..5ae95ea 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
index 0b8f1a9..b2b6a97 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
index 87bd502..cf1a769 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
index eb431b0..e0abcf4 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
index 4e448c8..3d0fbd6 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
index b756719..86b00415 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
index 466eca8..7bbae09 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
index 940fe5b..e9dca692 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java b/tools/layoutlib/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java
new file mode 100644
index 0000000..2fcec8e
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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 android.util;
+
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.android.BridgeContext;
+
+import org.junit.Test;
+import org.xmlpull.v1.XmlPullParser;
+
+import com.google.common.collect.ImmutableMap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BridgeXmlPullAttributesTest {
+    @Test
+    public void testGetAttributeIntValueForEnums() {
+        RenderResources renderResources = new RenderResources();
+
+        XmlPullParser parser = mock(XmlPullParser.class);
+        when(parser.getAttributeValue(BridgeConstants.NS_RESOURCES, "layout_width"))
+                .thenReturn("match_parent");
+        when(parser.getAttributeName(0)).thenReturn("layout_width");
+        when(parser.getAttributeNamespace(0)).thenReturn(BridgeConstants.NS_RESOURCES);
+        // Return every value twice since there is one test using name and other using index
+        when(parser.getAttributeValue("http://custom", "my_custom_attr"))
+                .thenReturn("a", "a", "b", "b", "invalid", "invalid");
+        when(parser.getAttributeName(1)).thenReturn("my_custom_attr");
+        when(parser.getAttributeNamespace(1)).thenReturn("http://custom");
+
+        BridgeContext context = mock(BridgeContext.class);
+        when(context.getRenderResources()).thenReturn(renderResources);
+
+        BridgeXmlPullAttributes attributes = new BridgeXmlPullAttributes(
+                parser,
+                context,
+                false,
+                attrName -> {
+                    if ("layout_width".equals(attrName)) {
+                        return ImmutableMap.of(
+                                "match_parent", 123);
+                    }
+                    return ImmutableMap.of();
+                },
+                attrName -> {
+                    if ("my_custom_attr".equals(attrName)) {
+                        return ImmutableMap.of(
+                                "a", 1,
+                                "b", 2
+                        );
+                    }
+                    return ImmutableMap.of();
+                });
+
+        // Test a framework defined enum attribute
+        assertEquals(123, attributes.getAttributeIntValue(BridgeConstants.NS_RESOURCES,
+                "layout_width", 500));
+        assertEquals(123, attributes.getAttributeIntValue(0, 500));
+        // Test non existing attribute (it should return the default value)
+        assertEquals(500, attributes.getAttributeIntValue(BridgeConstants.NS_RESOURCES,
+                "layout_height", 500));
+        assertEquals(500, attributes.getAttributeIntValue(2, 500));
+
+        // Test project defined enum attribute
+        assertEquals(1, attributes.getAttributeIntValue("http://custom",
+                "my_custom_attr", 500));
+        assertEquals(1, attributes.getAttributeIntValue(1, 500));
+        assertEquals(2, attributes.getAttributeIntValue("http://custom",
+                "my_custom_attr", 500));
+        assertEquals(2, attributes.getAttributeIntValue(1, 500));
+        // Test an invalid enum
+        boolean exception = false;
+        try {
+            attributes.getAttributeIntValue("http://custom", "my_custom_attr", 500);
+        } catch(NumberFormatException e) {
+            exception = true;
+        }
+        assertTrue(exception);
+        exception = false;
+        try {
+            attributes.getAttributeIntValue(1, 500);
+        } catch(NumberFormatException e) {
+            exception = true;
+        }
+        assertTrue(exception);
+
+        // Test non existing project attribute
+        assertEquals(500, attributes.getAttributeIntValue("http://custom",
+                "my_other_attr", 500));
+    }
+
+}
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
index 18c6629..cdf5633 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
@@ -54,7 +54,7 @@
      */
     private static final boolean FAIL_ON_MISSING_THUMBNAIL = true;
 
-    private static final int THUMBNAIL_SIZE = 250;
+    private static final int THUMBNAIL_SIZE = 1000;
 
     private static final double MAX_PERCENT_DIFFERENCE = 0.3;
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index dbf8cc1..97a15e4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -305,7 +305,9 @@
     /**
      * Priority determines the preference given to a network by {@code wpa_supplicant}
      * when choosing an access point with which to associate.
+     * @deprecated Priority is no longer used.
      */
+    @Deprecated
     public int priority;
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 0bfb955..f790332 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -263,11 +263,17 @@
         public static final int MSCHAPV2    = 3;
         /** Generic Token Card */
         public static final int GTC         = 4;
+        /** EAP-Subscriber Identity Module */
+        public static final int SIM         = 5;
+        /** EAP-Authentication and Key Agreement */
+        public static final int AKA         = 6;
+        /** EAP-Authentication and Key Agreement Prime */
+        public static final int AKA_PRIME   = 7;
         private static final String AUTH_PREFIX = "auth=";
         private static final String AUTHEAP_PREFIX = "autheap=";
         /** @hide */
         public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
-                "MSCHAPV2", "GTC" };
+                "MSCHAPV2", "GTC", "SIM", "AKA", "AKA'" };
 
         /** Prevent initialization */
         private Phase2() {}
@@ -426,6 +432,9 @@
             case Phase2.MSCHAP:
             case Phase2.MSCHAPV2:
             case Phase2.GTC:
+            case Phase2.SIM:
+            case Phase2.AKA:
+            case Phase2.AKA_PRIME:
                 mPhase2Method = phase2Method;
                 break;
             default:
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 3fb8ef3..ed6a166 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -838,7 +838,8 @@
     }
 
     /**
-     * Return a list of all the networks configured in the supplicant.
+     * Return a list of all the networks configured for the current foreground
+     * user.
      * Not all fields of WifiConfiguration are returned. Only the following
      * fields are filled in:
      * <ul>
@@ -1057,8 +1058,12 @@
      * Remove the specified network from the list of configured networks.
      * This may result in the asynchronous delivery of state change
      * events.
-     * @param netId the integer that identifies the network configuration
-     * to the supplicant
+     *
+     * Applications are not allowed to remove networks created by other
+     * applications.
+     *
+     * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        #getConfiguredNetworks}.
      * @return {@code true} if the operation succeeded
      */
     public boolean removeNetwork(int netId) {
@@ -1071,8 +1076,7 @@
 
     /**
      * Allow a previously configured network to be associated with. If
-     * <code>disableOthers</code> is true, then all other configured
-     * networks are disabled, and an attempt to connect to the selected
+     * <code>attemptConnect</code> is true, an attempt to connect to the selected
      * network is initiated. This may result in the asynchronous delivery
      * of state change events.
      * <p>
@@ -1089,14 +1093,17 @@
      * {@link Network#openConnection(java.net.URL)}, or
      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
      *
-     * @param netId the ID of the network in the list of configured networks
-     * @param disableOthers if true, disable all other networks. The way to
-     * select a particular network to connect to is specify {@code true}
-     * for this parameter.
+     * Applications are not allowed to enable networks created by other
+     * applications.
+     *
+     * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        #getConfiguredNetworks}.
+     * @param attemptConnect The way to select a particular network to connect to is specify
+     *        {@code true} for this parameter.
      * @return {@code true} if the operation succeeded
      */
-    public boolean enableNetwork(int netId, boolean disableOthers) {
-        final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
+    public boolean enableNetwork(int netId, boolean attemptConnect) {
+        final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
         if (pin) {
             NetworkRequest request = new NetworkRequest.Builder()
                     .clearCapabilities()
@@ -1107,7 +1114,7 @@
 
         boolean success;
         try {
-            success = mService.enableNetwork(netId, disableOthers);
+            success = mService.enableNetwork(netId, attemptConnect);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1123,7 +1130,12 @@
      * Disable a configured network. The specified network will not be
      * a candidate for associating. This may result in the asynchronous
      * delivery of state change events.
-     * @param netId the ID of the network as returned by {@link #addNetwork}.
+     *
+     * Applications are not allowed to disable networks created by other
+     * applications.
+     *
+     * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        #getConfiguredNetworks}.
      * @return {@code true} if the operation succeeded
      */
     public boolean disableNetwork(int netId) {
@@ -1182,15 +1194,11 @@
      * Check that the supplicant daemon is responding to requests.
      * @return {@code true} if we were able to communicate with the supplicant and
      * it returned the expected response to the PING message.
+     * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
      */
+    @Deprecated
     public boolean pingSupplicant() {
-        if (mService == null)
-            return false;
-        try {
-            return mService.pingSupplicant();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return isWifiEnabled();
     }
 
     /** @hide */
@@ -1509,14 +1517,18 @@
     }
 
     /**
-     * Tell the supplicant to persist the current list of configured networks.
+     * Tell the device to persist the current list of configured networks.
      * <p>
      * Note: It is possible for this method to change the network IDs of
      * existing networks. You should assume the network IDs can be different
      * after calling this method.
      *
      * @return {@code true} if the operation succeeded
+     * @deprecated There is no need to call this method -
+     * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
+     * and {@link #removeNetwork(int)} already persist the configurations automatically.
      */
+    @Deprecated
     public boolean saveConfiguration() {
         try {
             return mService.saveConfiguration();
@@ -2095,7 +2107,7 @@
 
     /**
      * Connect to a network with the given configuration. The network also
-     * gets added to the supplicant configuration.
+     * gets added to the list of configured networks for the foreground user.
      *
      * For a new network, this function is used instead of a
      * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
@@ -2124,8 +2136,8 @@
      * This function is used instead of a enableNetwork(), saveConfiguration() and
      * reconnect()
      *
-     * @param networkId the network id identifiying the network in the
-     *                supplicant configuration list
+     * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        getConfiguredNetworks}.
      * @param listener for callbacks on success or failure. Can be null.
      * @throws IllegalStateException if the WifiManager instance needs to be
      * initialized again
@@ -2137,9 +2149,9 @@
     }
 
     /**
-     * Save the given network in the supplicant config. If the network already
-     * exists, the configuration is updated. A new network is enabled
-     * by default.
+     * Save the given network to the list of configured networks for the
+     * foreground user. If the network already exists, the configuration
+     * is updated. Any new network is enabled by default.
      *
      * For a new network, this function is used instead of a
      * sequence of addNetwork(), enableNetwork() and saveConfiguration().
@@ -2160,7 +2172,8 @@
     }
 
     /**
-     * Delete the network in the supplicant config.
+     * Delete the network from the list of configured networks for the
+     * foreground user.
      *
      * This function is used instead of a sequence of removeNetwork()
      * and saveConfiguration().
@@ -2851,7 +2864,8 @@
 
     /**
      * Restore state from the older version of back up data.
-     * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
+     * The old backup data was essentially a backup of wpa_supplicant.conf
+     * and ipconfig.txt file.
      * @hide
      */
     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 7b73b4b..1f661c4 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -120,7 +120,7 @@
     public void setUpdateIdentifier(int updateIdentifier) {
         mUpdateIdentifier = updateIdentifier;
     }
-    public int getUpdateIdentififer() {
+    public int getUpdateIdentifier() {
         return mUpdateIdentifier;
     }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 025d4d3..620759d 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -100,7 +100,7 @@
     public void setCheckAaaServerCertStatus(boolean checkAaaServerCertStatus) {
         mCheckAaaServerCertStatus = checkAaaServerCertStatus;
     }
-    public boolean getCheckAaaServerStatus() {
+    public boolean getCheckAaaServerCertStatus() {
         return mCheckAaaServerCertStatus;
     }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 7a46129..8ec40c0 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -131,7 +131,7 @@
     public void setMatchAnyOis(long[] matchAnyOis) {
         mMatchAnyOis = matchAnyOis;
     }
-    public long[] getMatchAnysOis() {
+    public long[] getMatchAnyOis() {
         return mMatchAnyOis;
     }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
index caca0e4..63238e8 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -77,7 +77,7 @@
     public void setMinHomeDownlinkBandwidth(long minHomeDownlinkBandwidth) {
         mMinHomeDownlinkBandwidth = minHomeDownlinkBandwidth;
     }
-    public long getMinHomeDownlinkBandWidht() {
+    public long getMinHomeDownlinkBandwidth() {
         return mMinHomeDownlinkBandwidth;
     }
     private long mMinHomeUplinkBandwidth = Long.MIN_VALUE;
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index fa546a5..c4d2d32 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -283,6 +283,21 @@
         assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
     }
 
+    /** Verfies PEAP/SIM, PEAP/AKA, PEAP/AKA'. */
+    @Test
+    public void peapSimAkaAkaPrime() {
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.SIM);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=SIM\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setPhase2Method(Phase2.AKA);
+        assertEquals("\"auth=AKA\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setPhase2Method(Phase2.AKA_PRIME);
+        assertEquals("\"auth=AKA'\"", getSupplicantPhase2Method());
+    }
+
     /** Verfies that the copy constructor preseves the inner method information. */
     @Test
     public void copyConstructor() {